其实异步操作是可以被阻塞住的,只不过通常不是在处理消息时阻塞,而是在等待消息被触发时被阻塞.比如select函数,假如传入的最后一个timeout参数为NULL,那么如果所关注的事件没有一个被触发,程序就会一直阻塞在这个select调用处.而如果使用异步非阻塞的情况,比如aio_*组的操作,当我发起一个aio_read操作时,函数会马上返回不会被阻塞,当所关注的事件被触发时会调用之前注册的回调函数进行处理,具体可以参见我上面的连接给出的那篇文章.回到上面的例子中,如果在银行等待办理业务的人采用的是异步的方式去等待消息被触发,也就是领了一张小纸条,假如在这段时间里他不能离开银行做其它的事情,那么很显然,这个人被阻塞在了这个等待的操作上面;但是呢,这个人突然发觉自己烟瘾犯了,需要出去抽根烟,于是他告诉大堂经理说,排到我这个号码的时候麻烦到外面通知我一下(注册一个回调函数),那么他就没有被阻塞在这个等待的操作上面,自然这个就是异步+非阻塞的方式了.
同步和异步与阻塞与非阻塞是在通信和I/O中常用的字眼,之前在许多地方同步与阻塞,异步与非阻塞常常被混为一谈,带来了许多混乱,其实同步、异步和阻塞、非阻塞是两个不同的概念。最近随着异步IO(AIO)越来越多的应用,对这两个概念进行区分和解释的文章也越来越多,但是问起身边的同学,能说清楚的倒也不多,所以我就顺便跟风写一篇科普文吧(越来越水了=_=)。
同步(synchronous)和异步(asynchronous)其实是针对消息的发送和接受的次序而言的(在通信中就是消息的发送和接收,在IO中就是数据的读和写)。同步的意思就是消息的发送和接收是有序的,即接收和发送第二个包一定在第一个包之后第三个包之前,而不是乱序。异步的意思就是消息的发送和接收是可以乱序的,第一个包没发完可以直接发第二个包。
至于阻塞(block)和非阻塞(non-block)其实描述的是进程或线程进行等待时的一种方式。阻塞的意思是等待时进程或线程需要挂起,而非阻塞则是等待时线程或进程不需要被挂起,不影响线程的执行,这时线程或进程可以继续处理其它事物,不因为这个等待而受到影响(当然它仍然在等待这个消息,只不过可能会在线程或进程执行周期的某一个地方去查看消息的通知,而不是立即在原地等待)。
举个例子,两个人之间发短信,最简单的就是同步阻塞的方式,一个人发短信,然后啥也不干地等在手机前面,直到对方回信,接下来才发第二条短信(这时也确认了第一条短信已发到)。而同步非阻塞方式也就是大家常用的方式,则是发出去消息,然后去干别的事,(体现了非阻塞)等对方回短信之后(相当于确认了第一条短信已收到,并且有后续数据过来),再发第二条短信(体现了同步)。异步阻塞的方式,则是一口气发出几十条短信(由于中国移动并不保证发出短信的先后顺序,可能导致对方收到短信的顺序和发出去时不一致,这就体现了异步的概念,而且理论上发信的顺序也可以是乱的),发完之后就啥也不干,等对方一条一条的回信(这体现了阻塞的概念)。而如果在一口气发出几十条短信后没有傻傻的等待,而是去别的地方玩去了,对方的回信到一条读一条,则就变成异步非阻塞的方式了。
不知道通过上面的例子,大家是不是已经可以理解这两组概念之间的区别了。这里有篇相关的文章写得不错,如果还有些不理解的,可以再去阅读一下。由于国内在IT领域的起步落后国外(主要是美国)一些年份,再加上互联网的迅速普及,导致许多以讹传讹的现象时有发生。这两组本来适用范围并不相同的概念却在很长一段时间内被混为一谈,应该就是这方面的例子。这种错误增加了大家的学习成本,也不利于在某一些领域的进一步研究,所以个人以为搞清楚这些概念还是很有必要的(最后为自己的又一篇水文开脱一下=_=)
这些词之间的区别难倒了很多人,还有什么同步阻塞, 同步非阻塞, 异步阻塞, 异步非阻塞,乱七八糟的。
很多文章也想讲明白这个问题。著名且引起热议的有
http://www.ibm.com/developerworks/cn/linux/l-async/
http://www.cppblog.com/converse/archive/2009/05/13/82879.html
可是看了之后还是有点将信将疑,跑到图书馆翻了UNP 第一卷,不愧是圣经级别的著作,似有所悟。
UNP所述:
POSIX定义中,同步IO操作:IO操作将导致请求进程阻塞,直到IO操作完成。
异步IO操作:IO操作不导致请求进程阻塞
UNP中总结的IO模型有5种之多
阻塞IO,非阻塞IO,IO复用,信号驱动IO,异步IO,前四种都属于同步IO。
阻塞IO不必说了
非阻塞IO ,IO请求时加上O_NONBLOCK一类的标志位,立刻返回,IO没有就绪会返回错误,需要请求进程主动轮询不断发IO请求直到返回正确
IO复用同非阻塞IO本质一样,不过利用了新的select系统调用,由内核来负责本来是请求进程该做的轮询操作。看似比非阻塞IO还多了一个系统调用开销,不过因为可以支持多路IO,才算提高了效率
信号驱动IO,调用sigaltion系统调用,当内核中IO数据就绪时以SIGIO信号通知请求进程,请求进程再把数据从内核读入到用户空间,这一步是阻塞的。
异步IO,如定义所说,不会因为IO操作阻塞,IO操作全部完成才通知请求进程。
这样以来,同步和阻塞,异步和非阻塞就不会被混淆了,它们不是同一个方面上的概念,不能比较区别
同步和异步是只跟IO操作过程中进程的状态变化有关
阻塞和非阻塞就是进程的两种状态。