一、 IO多路复用
IO多路复用模型是通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。
我们可以把标准输入、套接字等都看做 I/O 的一路,多路复用的意思,就是在任何一路 I/O 有“事件”发生的情况下,通知应用程序去处理相应的 I/O 事件,这样我们的程序,在同一时刻仿佛可以处理多个 I/O 事件。使用 I/O 复用以后,如果标准输入有数据,立即从标准输入读入数据,通过套接字发送出去;如果套接字有数据可以读,立即可以读出数据。这些 I/O 事件的类型非常多,比如:
标准输入文件描述符准备好可以读;
监听套接字准备好,新的连接已经建立成功;
已连接套接字准备好可以写。
二、多路复用的技术
1.SELECT
select 函数就是这样一种常见的 IO 多路复用技术。使用 select 函数,通知内核挂起进程,当一个或多个 I/O 事件发生后,控制权返还给应用程序,由应用程序进行 I/O 事件的处理。
select 通过描述符集合来表示检测的 I/O 对象,通过三个不同的描述符集合来描述 I/O 事件 :可读、可写和异常。但 select 有一个缺点,那就是所支持的文件描述符的个数是有限,
在 Linux 系统中,select 的默认最大值为 1024。另外还有用户态 - 内核态频繁的数据拷贝。
2.POLL
poll 是除了 select 之外,另一种普遍使用的 IO 多路复用技术,和 select 相比,它和内核交互的数据结构有所变化,另外,也突破了文件描述符的个数限制。和 select 函数对比一下,
我们发现 poll 函数和 select 不一样的地方就是,在 select 里面,文件描述符的个数已经随着 fd_set 的实现而固定,没有办法对此进行配置;而在 poll 函数里,我们可以控制 pollfd 结构的数组大小,
这意味着我们可以突破原来 select 函数最大描述符的限制。但其也是采用遍历的方式来判断是否有设备就绪,所以效率比较低,另外一个问题是大量的fd数组在用户空间和内核空间之间来回复制传递,
也浪费了不少性能。
3.EPOLL
epoll 可以说是和 poll 相似的一种 IO 多路复用技术。本质上 epoll 还是一种 I/O 多路复用技术, epoll 通过监控注册的多个描述字,来进行 I/O 事件的分发处理。epoll 通过改进的接口设计,
避免了用户态-内核态频繁的数据拷贝,大大提高了系统性能。不同于 poll 的是,epoll 不仅提供了默认的 level-triggered(条件触发)机制,还提供了性能更为强劲的 edge-triggered(边缘触发)机制。
条件触发的意思是只要满足事件的条件,比如有数据需要读,就一直不断地把这个事件传递给用户; 边缘触发的意思是只有第一次满足条件的时候才触发,之后就不会再传递同样的事件了。