IO模型浅析-阻塞、非阻塞、IO复用、信号驱动、异步IO、同步IO

最近看到OVS用户态的代码,在接收内核态信息的时候,使用了Epoll多路复用机制,对其十分不解,因而从网上找了一些资料,学习了一下《UNIX网络变成卷1:套接字联网API》这本书对应的章节,网上虽然关于该主题的博文不少,而且讲解的很详细,可是在这里仍是作一个学习笔记,记录一下本身的想法。html

IO模型

在《UNIX网络变成卷1:套接字联网API》这本书中,提到了五种I/O模型,分别为:阻塞式I/O、非阻塞式I/O、I/O复用(Epoll、select都是一种I/O复用机制),信息驱动式I/O、异步I/O,下面具体的一一介绍。linux

阻塞式I/O模型

阻塞,顾名思义,当进程在等待数据时,若该数据一直没有产生,则该进程将一直等待,直到等待的数据产生为止,这个过程当中进程的状态是阻塞的。segmentfault

1470567-20180911212150626-466712910.png

如上图所示,在linux中,用户态进程调用recvfrom系统调用接收数据,当前内核中并无准备好数据,该用户态进程将一直在此等待,不会进行其余的操做,待内核态准备好数据,将数据从内核态拷贝到用户空间内存,而后recvfrom返回成功的指示,此时用户态进行才解除阻塞的状态,处理收到的数据。markdown

从上述过程能够看出,用户态接收内核态数据的时候,主要有两个过程:内核态得到数据-->将数据从内核态的内存空间中复制到用户态进程的缓冲区中网络

非阻塞式I/O模型

在非阻塞式I/O模型中,当进程等待内核的数据,而当该数据未到达的时候,进程会不断询问内核,直到内核准备好数据。多线程

1470567-20180911212211998-1577621768.png

如上图,用户态进程调用recvfrom接收数据,当前并无数据报文产生,此时recvfrom返回EWOULDBLOCK,用户态进程会一直调用recvfrom询问内核,待内核准备好数据的时候,以后用户态进程再也不询问内核,待数据从内核复制到用户空间,recvfrom成功返回,用户态进程开始处理数据。异步

须要注意的是,当数据从内核复制到用户空间中的这一段时间中,用户态进程是处于阻塞的状态的。post

非阻塞式I/O模型,我的以为这个名字可能有点混淆,并非和阻塞式模型是彻底对立的,不是说进程等不到数据,就去作别的事情,偏偏进程这个时候一直在原地等待数据的到来,与阻塞式模型不一样的是,非阻塞至关于进程一直在敲门问“数据好了么,快给我”,而后房门后的人说“没有准备好,请稍后!”,这个过程是一种轮询的状态,而阻塞式是佛系的态度,敲了一次门,房门后的人没有给任何回应,因而就去睡觉,啥都不作,直到房门后的人作出响应叫醒他,进程才去作下一步动做。性能

I/O复用模型

在ovs的用户态源码里,就用到了I/O复用模型,在计算机网络里面,有不少关于“复用”的用法,好比多路复用,意思就是原本一条链路上一次只能传输一个数据流,若是要实现两个源之间多条数据流同时传输,那就得须要多条链路了,可是复用技术能够经过将一条链路划分频率,或者划分传输的时间,使得一条链路上能够同时传输多条数据流。学习

1470567-20180911212233268-507747906.png

套用到I/O复用模型上,能够对应到以下应用场景:若是一个进程须要等到多种不一样的消息,那么通常的作法就是开启多条线程,每一个线程接收一类消息,若是每一个线程都是采用阻塞式I/O模型,那么每一个线程在消息未产生的时候就会阻塞,也就是说在多线程中使用阻塞式I/O。I/O复用就是基于上述的场景中,无需采用多线程监听消息的方式,进程直接监听全部的消息类型,这其中就涉及到select、poll、epoll等不一样的方法。

如上图所示,用户态进程采用select的方法,经过select能够等待多个不一样类型的消息,若是其中有一个类型的消息准备好,则select会返回信息,而后用户态进程调用recvfrom接收数据。

能够将select复用机制看做是一个描述符集合的管理,进程经过向这个集合中放入不一样的描述符,用来等待不一样的消息产生,而后经过select统一的进行管理,让其能够同时等待这个集合中任意一个事件的产生。

I/O复用和阻塞式I/O很类似,不一样的是,I/O复用等待多类事件,阻塞式I/O只等待一类事件,另外,在I/O复用中,会产生两个系统调用(如上图,select和recvfrom),而阻塞式I/O只产生一个系统调用。那么这就涉及到具体的性能问题,当只存在一类事件的时候,使用阻塞式I/O模型的性能会更好,当存在多种不一样类型的事件时,I/O复用的性能要好的多,由于阻塞式I/O模型只能监听一类事件,因此这个时候须要使用多线程进行处理。

信号驱动式I/O模型

在信号驱动式I/O模型中,与阻塞式和非阻塞式有了一个本质的区别,那就是用户态进程再也不等待内核态的数据准备好,直接能够去作别的事情。

1470567-20180911212247565-1745374446.png

如上图所示,当须要等待数据的时候,首先用户态会向内核发送一个信号,告诉内核我要什么数据,而后用户态就无论了,作别的事情去了,而当内核态中的数据准备好以后,内核立马发给用户态一个信号,说”数据准备好了,快来查收“,用户态进程收到以后,立马调用recvfrom,等待数据从内核空间复制到用户空间,待完成以后recvfrom返回成功指示,用户态进程才处理别的事情。

经过上面的图,能够看出信号驱动式I/O模型有种异步操做的赶脚,可是在将数据从内核复制到用户空间这段时间内用户态进程是阻塞的

异步I/O模型

异步I/O模型相对于信号驱动式I/O模型就更完全了。

1470567-20180911212303743-33188013.png

如上图,首先用户态进程告诉内核态须要什么数据(上图中经过aio_read),而后用户态进程就无论了,作别的事情,内核等待用户态须要的数据准备好,而后将数据复制到用户空间,此时才告诉用户态进程,”数据都已经准备好,请查收“,而后用户态进程直接处理用户空间的数据。

在复制数据到用户空间这个时间段内,用户态进程也是不阻塞的

同步I/O

《UNIX网络变成卷1:套接字联网API》这本书中,并无把同步I/O做为一种单独的I/O模型来讲明,在没有阅读这些资料以前,我一直认为阻塞式I/O等同于同步I/O,非阻塞式I/O等同于异步I/O,可见不能单纯的经过字面意思就进行判断。

经过对上述几种I/O模型的描述中,能够获得一个结论:阻塞式I/O、非阻塞式I/O、I/O复用模型是同步I/O模型,由于在等待数据的过程当中,这三种模型中的进程都没有去作别的事情,即使是非阻塞式的轮询,也能够看做是一种同步。

同时书中也认为信号驱动式I/O模型是同步I/O,书中说到:POSIX将同步IO操做定义为“致使请求进程阻塞,直到I/O操做完成”,而书中认为在信号驱动式I/O模型中等待数据的那段时间不算是真正的I/O操做(由于没有调用I/O相关的系统调用),而数据从内核复制到用户空间才是真正的I/O操做(这个时候调用了recvfrom系统调用)。

I/O模型比较

书中的这张图表述的很是清楚,从等待数据和数据复制这两个时间段,指出了不一样I/O模型的区别,这里再也不赘述。

1470567-20180911212315919-1077504877.png

总结

从网上看了不少资料,不一样的博主对这五个模型总结的状况不一样,无一例外,基本都采用一个生活场景来描述他们的不一样,可是我我的以为有些场景描述太过简单,没有将不一样模型的区别描述彻底,在这里我也举一个生活中的场景做为总结,固然这只是我本身的想法,不妥之处评论区能够指出。

咱们去餐厅吃饭,会通过如下几个步骤:首先根据菜单点菜,而后等待厨房准备好,接着服务员上菜。在这个场景中,等待厨房准备菜肴等同于等待数据,服务员上菜等同于将数据从内核复制到用户空间,你就是用户态进程了,服务员和饭店看做是内核态的进程。

阻塞式I/O模型:只点一个菜,而后在餐桌上开始等待,在这个过程当中什么事都不干,等服务员把菜上到桌子上以后才开始大快朵颐。

非阻塞式I/O模型:只点一个菜,而后开始等待,啥事都不作,等了一下子而后就去问服务员,“个人菜好了吗?”,没好接着等待,过了一下子而后又跑去问....重复这个过程,直到服务员说“亲,你的菜好了,我如今给您送桌上去”,而后你坐在桌子上,等待服务员把饭菜送到你的餐桌上,才开始吃饭。

I/O复用模型:你点了不少菜,而后开始等待,某个时刻其中一个菜或者多个菜厨房里同时好了,服务员跑过来讲,“亲,您的有些菜好了,要如今上桌么?”, 你回答,如今就上,因而服务员上一个菜(服务员一次只能上一个菜),你就吃完一个,上一个你就吃完一个。。。

信号驱动式I/O模型:只点一个菜,而后给服务员留下手机,告诉他菜准备好了打个电话给你,先不要上菜,而后你就出去玩耍了,等到菜好了,服务员手机通知你,你立马回到了餐厅,对服务员说“你如今能够上菜了”,因而你在餐桌上等待服务员把菜送上来,而后吃饭。

异步I/O模型:只点一个菜,而后给服务员留下手机,告诉他菜准备好了先上菜,菜上桌了打电话给你,而后你就出去玩耍了,等到菜上桌了,服务员手机通知你,你立马回到了餐桌,开始吃饭。

参考资料

UNIX网络变成卷1:套接字联网API
网络IO之阻塞、非阻塞、同步、异步总结
IO - 同步,异步,阻塞,非阻塞 (亡羊补牢篇)

做者:yearsj
转载请注明出处:https://www.cnblogs.com/yearsj/p/9630440.html
segmentfault对应博文:http://www.javashuo.com/article/p-kxakmnzy-hy.html

转载于:https://www.cnblogs.com/yearsj/p/9630440.html