阻塞/非阻塞/同步/异步
首先结论如下:
对于unix
来说:
- 阻塞式I/O(默认)
- 非阻塞I/O(nonblock)
- I/O复用(select/poll/epoll)
都是同步I/O,因为它们在数据由内核空间复制回进程缓冲区时都是阻塞的(不能干别的事)。
AIO
异步I/O模型
它是异步I/O,因为异步I/O是这个含义:
- 数据准备完成
- 由内核空间拷贝回缓冲区后 并通知进程
在进程收到通知前这段时间,是没有阻塞的(即不被挂起,可以做其他事).
而对于windows
来说,只有IOCP模型
是异步I/O
.
总结起来为:
在处理 IO 的时候,阻塞和非阻塞都是同步 IO。
只有使用了特殊的 API 才是异步 IO。
理解:
首先解释一下阻塞/非阻塞
和同步/异步
在层次上的不同.
阻塞/非阻塞
是从"我"这个单进程角度看的,比如"我"要读数据,但数据没准备好,不可读.此时我要是一直等待下去,那我就是阻塞
的. 不等待而是继续向下执行,那我就是非阻塞
的.
同步/异步
是从多进程或者是进程与OS之间协作关系来看的,下面详细分析.
例子:
"我"是一个进程,我去买书(读数据),我要买<<UNP>>. 书店老板是OS内核.
非阻塞的情况有:
- 我立即买到了或者书店告诉我没有此书,我就走了.
- 书店老板告诉我先忙,一会再来问问. (即程序中使用
nonblock,select,poll,epoll,
即我先返回不阻塞在这里,但我要时常来检查这个fd是否可读. 这个期间这个fd别人是用不了的). - 书店老板通知我现在没书,有书的时候
通知
我自己来拿. 实际上这个就是信号驱动模型
,这里同样属于同步I/O
阻塞的情况是:
- 书店告诉我没书,那我一直等下去,直到有书(或者设置一个时限).那排在我后面的人也会阻塞.
好,到目前为止,以上这些情况都是同步I/O.
异步I/O情况如下:
- 书店告诉我没书,但老板说我可以做其他事,有书时他会将书送过来(不是自己去取).
这里我们可以发现,"买书"就是一个system call(会从用户模式到内核模式),其中"老板将书送给我"即将数据从内核模式拷贝到进程缓存区中.
进一步的,我们理解异步I/O和同步I/O(尤其是非阻塞I/O)的含义:
针对同一个fd来说,同步I/O一定要按照 I/O操作请求,进行I/O操作并得到结果,这个顺序来执行.即必须有这两个操作.而异步I/O呢,我可以只发出请求,而不进行操作,其他进程或者是OS内核帮我操作完成并通知我.
- 同步I/O中的非阻塞I/O :
它和异步I/O一样不会阻塞当前"我"这个进程, 但是OS内核可能不会通知"我"I/O已准备好(需要我这个进程去时常查询),或者是通知"我"I/O已准备好,但仍然需要"我"自己进行操作I/O得到I/O结果(即"信号驱动"). 这里自己操作I/O实际上就是从内核把数据复制到我这个进程上. - 异步I/O:
OS内核会通知"我"I/O操作已完成,即OS内核已经将数据拷贝到我这个进程上了.我只管使用就可以了.
故针对unix服务器开发中的I/O模型,有5类:
- 阻塞I/O
- 非阻塞I/O(nonblock)
- I/O复用(select poll epoll)
- 信号驱动
- 异步I/O(AIO模型)
前四类为同步I/O,I/O复用和信号驱动模型都可用于非阻塞I/O.
只有最后一个模型为异步I/O