UNPv1 第 6.2 节总结了 Unix/Linux 上的五种 IO 模型:
阻塞(blocking)、
非阻塞(non-blocking)、
IO 复用(IO multiplexing)、
信号驱动(signal-driven)、
异步(asynchronous)。
这些都是单线程下的 IO 模型。
-
blocking I/O
首先application调用 recvfrom()转入kernel,注意kernel有2个过程,wait for data和copy data from kernel to user。直到最后copy complete后,recvfrom()才返回。此过程一直是阻塞的。
-
nonblocking I/O:
与blocking I/O对立的,非阻塞套接字,调用过程图如下:
可以看见,如果直接操作它,那就是个轮询。。直到内核缓冲区有数据。
-
I/O multiplexing (select and poll)
最常见的I/O复用模型,select。
select先阻塞,有活动套接字才返回。与blocking I/O相比,select会有两次系统调用,但是select能处理多个套接字。
-
signal driven I/O (SIGIO)
只有UNIX系统支持,感兴趣的课查阅相关资料
与I/O multiplexing (select and poll)相比,它的优势是,免去了select的阻塞与轮询,当有活跃套接字时,由注册的handler处理。
-
asynchronous I/O (the POSIX aio_functions)
完全异步的I/O复用机制,因为纵观上面其它四种模型,至少都会在由kernel copy data to appliction时阻塞。
而该模型是当copy完成后才通知application,可见是纯异步的。
下面是以上五种模型的比较
可以看出,越往后,阻塞越少,理论上效率也是最优。
=====================分割线==================================
实际上,不管是哪种模型,都可以抽象一层出来,提供一致的接口,广为人知的有ACE,Libevent这些,他们都是跨平台的,而且他们自动选择最优的I/O复用机制,用户只需调用接口即可。
说到这里又得说说2个设计模式,Reactor and Proactor。Libevent是Reactor模型,ACE提供Proactor模型。实际都是对各种I/O复用机制的封装。