浅谈Node 异步IO和事件循环

2020-06-17 07:11:51易采站长站整理

异步 I/O(asynchronous IO)

用户进程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。

而在Node中, 采用的是I/O 多路复用的模式, 而在I/O多路复用的模式中, 又具有read, select, poll, epoll等几个子模式, Node采用的是最优的epoll模式, 这里简单说下其中的区别, 并且解释下为什么epoll是最优的。

read

read。它是一种最原始、性能最低的一种,它会重复检查I/O的状态来完成数据的完整读取。在得到最终数据前,CPU一直耗用在I/O状态的重复检查上。图1是通过read进行轮询的示意图。

select

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

poll

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

epoll

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

除此之外, 另外的poll和select还具有以下的缺点(引用自 文章 ):

每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大
同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大