IO——同步、异步、阻塞、非阻塞
IO类型
一般情况下:IO又五种类型
BlockingIO: 阻塞型的IO
NonBlockingIO:非阻塞型的IO
IO multiplexing : IO多路服用
signal driven IO:信号量驱动IO
asynchronous IO:异步 IO
但是 signal driven IO 一般不常见,所以一般情况下我们只用四种IO。
IO分类介绍
Blocking IO——阻塞型的IO
在默认的情况下,Linux所有的Socket都是Blocking的,一个典型的读操作流程大概是这样:
从图中可以看出,用户进程调用了 recvfrom 接收数据的系统调用,整个过程分以下几步:
- 用户应用调用 recvfrom 系统调用
- kernel 查看有木有准备好的数据,如果木有,那么阻塞等待数据准备好。
- 有数据后,把内核内存的 数据拷贝到 用户内存 中,这个拷贝过程也是阻塞的。
- 拷贝完成之后,内核返回用户 拷贝完了,这个时候用户进程才开始处理数据。
特点: 对于用户进程来说,不管是 等待数据准备好 还是 数据拷贝 这两个过程,用户进程一直是被阻塞的。
NonBlocking IO——非阻塞的IO
非阻塞的IO流程如下:
- 当用户进程发出 recvfrom 操作时,如果 kernel 中的数据还没有准备好,那么它并不会阻塞用户进程,而是立刻返回一个 Error。
- 用户进程角度接收到 Error ,它发起一个 recvfrom 操作后,并不需要等待,而是马上就得到了一个结果。用户进程判断结果是一个 Error时 ,它就知道数据还没有准备好,先坐一会儿其他的时,等一会儿发一个 recvfrom 操作。
- 若用户端接收的不是OK,那么继续重复步骤2,如果时return OK ,那么用户就等待数据从内核内存拷贝到用户内存。
- 拷贝完了就进行数据处理
特点:用户进程其实是需要不断的主动询问kernel数据好了没有。
IO multiplexing : IO多路服用
实际上 IO multiplexing 就是我们经常说的select/poll,poll的意思时轮询。也有的地方成为这样的IO是
event driven IO(事件驱动IO),select/poll的好处就是单个线程的process就能处理多个网络请求,它的基本原理就是select/poll方法会不断的轮询所负责的socket,当某一个socket有数据到达了,就通知用户进程。
步骤:
- 用户调用select,用户的整个进程被block,等待内核监听select负责的socket中有数据返回。
- 当有任意一个socket数据准备好了,select就返回,阻塞等待数据从内核内存复制到用户内存。
- 复制完处理数据
是不是感觉这个和阻塞的IO很像,是的,的确是很像,但是select/poll的特点就是同时处理多个链接。
多路复用的IO和阻塞的IO 比,多路复用的IO有两个系统调用,select 和 recvfrom,而阻塞的IO只有一个系统调用 recvfrom。
事实上,如果用户链接不多的话,阻塞的IO的服务器性能可能更好一些。多路复用延迟还更大。
Asynchronous I/O——异步IO
具体步骤:
- 用户进程发器read 读操作之后,kernel返回 立刻就可以开始去做其他的事。不阻塞
- kernel完成数据准备操作,完成后给进程发一个指定的signal信号.
- 用户进程接收到signal信号之后就,处理准备好的数据。
总结
-
Blocking IO阻塞 和 NonBlocking IO非阻塞的区别是啥?
答:Blocking IO阻塞: 无论是数据准备还是数据从内核内存拷贝到用户内存,用户进程都是阻塞的。知道对应的进程操作完成
**NonBlocking IO非阻塞: **数据准备阶段是每隔一段时间去问一下数据有木有准备好,一旦问的返回是OK,才阻塞等待数据从内核内存拷贝到用户内存。 -
同步IO和异步IO的区别
借用国外大佬的几句话:
A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes;
An asynchronous I/O operation does not cause the requesting process to be blocked;
这两句话的意思是说,同步IO操作会导致请求进程被阻塞,除非IO操作完成
异步IO操作不会导致请求的进程被阻塞
这么说的话:
Blocking IO(阻塞)、 NonBlocking IO(非阻塞)、IO multiplexing (多路复用)都是同步IO。
分别说一下原因:
Blocking IO : 这个不要多说了,用户进程是请求的进程,阻塞的IO操作 一直会导致用户进程被阻塞。
这一定是同步IO了
NonBlocking IO: 这个有点理解困难,为什么说非阻塞IO也是同步IO呢?因为定义的 I/O operation(IO操作)是真实的IO操作。上面的图中 recvfrom的时候,如果数据没有准备好,那么这个时候是不会阻塞用户进程的,但是如果数据准备好了,那么就一定会阻塞用户进程,把数据从内核内存往用户进程拷贝。
**IO multiplexing: ** 这个就更不用说了,select等内核返回这段时间用户进程是BLock的,recvfrom 拷贝数据,这一段时间还是Block的。
下面是各个IO的比较图:
通过文字和图片,相比大家应该有一定的理解了。
最难的就是理解Non Blocking IO 是同步IO了,虽然它绝大部分时间是不会被block的,但是它仍然要求进程去主动check,并且数据准备好以后,也需要recvfrom 来将数据拷贝到用户内存。
而 Asynchronous IO 则完全不同,它就像是用户进程只发送一个命令,然后整个IO过程都是由内核完成的。然后内核给用户进程信号,在此期间,用户进程是不需要主动的去拷贝数据的。
笔者打一个近似的比方:
A,B,C,D 四个开发商,建设楼盘。
A开发商比较笨,开发的楼盘也小,他每天都在工地看开发的怎么样了,直到开发完成(建设 + 收尾),才去启动下一步计划——阻塞IO。
B开发商稍微能力强一些,他不每天在工地,而是隔一段时间去看,直到工程收尾他真正的去手把手指导收尾。
C能力更强,负责多个楼盘的开发,每一个楼盘都进度都不一样,他给每个楼盘设置负责人,那个楼盘进入收尾了,就给他打电话,然后他就去处理收尾。
D是真正的大佬,他直接把手里的楼盘全权承包出去,自己才是楼盘的所有者,承包商 把 建设和收尾都做了,他坐享其成。
参考博文
historyasamirror博主: IO - 同步,异步,阻塞,非阻塞 (亡羊补牢篇).
IBM: 使用异步 I/O 大大提高应用程序的性能.