LinuxIO模型概述

前言

一个socket进程进行一次read可以分成两个阶段,等待数据是否准备好,以及数据从内核copy到用户空间。 我们举个例子,肚子饿了要去小吃街吃拉面,在我们正式开始吃面之前需要1.先等拉面师傅做好面,2.然后把做好的面放到我们的桌子上。

阻塞和非阻塞

阻塞和非阻塞,主要是针对事情的本身,指做一件事后能不能返回一个结果。阻塞就是一直等待到事情做完才返回,非阻塞就是立马返回一个消息(没做好或者已经做好)。如果是阻塞进程read一直等待,进程控制权就没了,要阻塞两个阶段,数据到来和数据从内核copy到进程缓冲区。非阻塞则是read一发出立马返回一个错误信息,程序里必须不断去read直到数据到达返回可读消息,然后进程阻塞把数据从内核缓冲区copy到进程缓冲区,实际阻塞的是后面取数据的阶段。 继续上面的例子,下单之后等待师傅做面的过程,我们可以一直傻乎乎地在旁边等着师傅做好。也可以先去其他地方玩玩,然后时不时一会儿跑回来问下师傅有没有做好,有没有做好...前者就是阻塞,后者就是非阻塞。等到师傅师傅做好了,我把面端回来到桌子上,这部分也是阻塞的。

对于阻塞和非阻塞而言,如果针对一个IO,非阻塞根本没阻塞的效率高。而且相对于阻塞而言,非阻塞是轮询要发出很多次系统调用的,而且很多次都是空轮询,看起来毫无优势可言。但是非阻塞IO因为等待数据阶段是非阻塞的,所以可以同时进行很多个IO操作。 继续上面的例子,我点完面之后还想去吃小笼包,还有奶茶。如果是阻塞,那么我必须等面做好了,我再去奶茶店等奶茶,等奶茶好了再去等小笼包。如果是非阻塞,我点了面后,跑到奶茶店点奶茶,然后再去小笼包店点小笼包,然后开始轮着跑三家店是否准备好了,够累的的吧?

IO多路复用

尽管非阻塞支持同时多IO,但是资源上还是很浪费,存在很多空轮询。于是出现了一种新的IO模型,叫做IO多路复用模型,最早的就是select模型和poll模型,两者开始的区别只是平台不同,而且前者有最大监控描述符限制,但是功能上差不多。select模型支持一次性监控一大堆感兴趣的IO事件发生的描述符集合,一旦有一个或多个IO准备就绪,就返回所有描述符集合。然后扫描返回列表,找到有可读或者可写的描述符,可能是一个也可能多个,进行相应第二阶段读取或者写入数据。select模型调用的时候也是阻塞的,只是它支持多路IO前提下减少了不必要的空轮询。 继续上面的例子,我为了能吃面和奶茶,小笼包三家店轮着跑而累的气喘吁吁,这时候小吃街上多了一块大屏幕,里面有各个店准备小吃的状态,比如小笼包正在做,面已经做好了,等等,我就是只需要看着大屏幕就可以了,然后筛选下哪些是已经做好了,我就去店里面取,再也不需要来回挨家挨户跑了。这个大屏幕的出现就是select模型。

select模型最大的优点就是跨平台性好,估计也就只剩这个优点了。看看它的缺点,1. 首先支持的监控的描述符集合数量有限制,内核参数决定的。2. 每次select调用进程是阻塞的,并且需要把描述符集合从用户态copy到内核态,一旦数量增加,资源消耗线性增加。3. select返回的描述符是没有经过筛选的,上面有些有IO需求,有些没有。 还是采用上面的例子,尽管有了大屏幕,你还是得等,常常去看看大屏幕。其次大屏幕上对于那些没做好的小吃对我是没有用的,我只关注做好的,还得我人工筛选,有点笨。总之,一旦我买的东西很多很多,就会很麻烦。

可以查看之前的Linux IO模型介绍

更新的多路复用技术epoll出现了,几乎没有最大描述符数量限制,epoll实现很复杂,每个描述符注册到内核里,只需要一次,每个socket都是非阻塞,对于每个描述符都设计了callback,而且epoll返回的都是可用的描述符集合,不需要再扫描一遍寻找可IO的描述符。epoll还支持两种触发模型,epoll水平触发和边缘触发

同步和异步

再说点同步和异步的区别,这两者主要是针对发起者而言,是指做发出指令要做一件事后是否撒手不管,计算机上看是IO系统调用后本身实现的一个逻辑而已。 对于同步,就是发出指令要去做一件事,为了知道结果,所以可能一直去等待,或者不断去轮询是否做好。而异步则是发出指令要做一件事,不管结果直接返回去做其它事情,然后等待通知,这就算是异步。在计算机上看是针对进程发出IO请求后与内核交互的过程。同步就是IO发出后进程还一直在关注IO是否完成,要么阻塞,要么轮询等待结果。而异步是用户进程发出IO请求后立马返回去做其它事情,直到内核等待数据并且把数据准备好通知进程算是异步。重点就是在通知上!对于同步才会有阻塞或者非阻塞的概念,对于异步,没什么阻塞和非阻塞了。

继续上面的例子,去小吃街吃面,如果是同步机制,点了面之后我就要么一直等待着(同步阻塞),等待师傅把面做好,或者我时不时一会儿跑过去问下师傅面做好了没(同步非阻塞)。等到师傅面做好了,我再把面端回桌子(这个过程由我自己完成,也算阻塞)。 如果是异步机制,我在点面的时候留了一个手机号码,然后告诉师傅我坐几号桌,然后就可以安心去逛街了,等到师傅把面做好了,师傅会自己把面端到我指定的桌子上,然后发短信告诉我面已经按照我的要求准备好了,所以异步的效率肯定是最好的。

标签:none