Skip to content

异步IO与非阻塞IO

异步I/O与非阻塞I/O

操作系统对计算机进行了抽象,将所有输入输出设备抽象为文件。内核在进行文件I/O操作时,通过文件描述符进行管理,而文件描述符类似于应用程序与系统内核之间的凭证。应用程序如果需要进行I/O调用,需要先打开文件描述符,然后再根据文件描述符去实现文件的数据读写。

非阻塞I/O与阻塞I/O的区别在于阻塞I/O完成整个获取数据的过程,而非阻塞I/O则不带数据直接返回,要获取数据,还需要通过文件描述符再次读取。

An image

非阻塞I/O返回之后,CPU的时间片可以用来处理其他事务,此时的性能提升是明显的。但非阻塞I/O也存在一些问题。**由于完整的I/O并没有完成,立即返回的并不是业务层期望的数据,而仅仅是当前调用的状态。为了获取完整的数据,应用程序需要重复调用I/O操作来确认是否完成。**这种重复调用判断操作是否完成的技术叫做轮询。

An image

阻塞I/O造成CPU等待浪费,非阻塞带来的麻烦却是需要轮询去确认是否完全完成数据获取,它会让CPU处理状态判断,是对CPU资源的浪费。

轮询技术

read

read是最原始、性能最低的一种,通过重复调用来检查I/O的状态来完成完整数据的读取。在得到最终数据前,CPU一直耗用在等待上。

An image

select

select是在read的基础上改进的一种方案,通过对文件描述符上的事件状态来进行判断。select轮询具有一个较弱的限制,那就是由于它采用一个1024长度的数组来存储状态,所以它最多可以同时检查1024个文件描述符。

An image

poll

该方案较select有所改进,采用链表的方式避免数组长度的限制,其次它能避免不需要的检查。但是当文件描述符较多的时候,它的性能还是十分低下的。

An image

epoll

epoll是Linux下效率最高的I/O事件通知机制,在进入轮询的时候如果没有检查到I/O事件,将会进行休眠,直到事件发生将它唤醒。它是真实利用了事件通知、执行回调的方式,而不是遍历查询,所以不会浪费CPU,执行效率较高。

An image

轮询技术满足了非阻塞I/O确保获取完整数据的需求,但是对于应用程序而言,它仍然只能算是一种同步,因为应用程序仍然需要等待I/O完全返回,依旧花费了很多时间来等待。等待期间,CPU要么用于遍历文件描述符的状态,要么用于休眠等待事件发生。结论是它不够好。