select/poll/epoll 是操作系统提供的三种 I/O 多路复用机制,它们的作用是同时监控多个文件描述符的状态,以便在有数据可读或可写时进行相应的处理。本文将分别介绍这三种机制的特点和区别。

1. select

select 是最早出现的 I/O 多路复用机制,最初在 BSD Unix 上实现。它采用线性扫描的方式依次检查所有的文件描述符,当某个文件描述符就绪时返回给用户进程。select 整体上是同步阻塞的,即调用 select 时,进程会被阻塞,直到有描述符就绪才会返回。select 将文件描述符的状态集中保存在用户空间的数据结构中,每次调用 select 前都需要将文件描述符状态集拷贝到内核空间,因此,select 对文件描述符数量有一定限制,通常默认是 1024。

select 的优点是:实时性好,可以处理大量的并发连接。

select 的缺点是:效率低下,每次调用 select 都需要将整个文件描述符状态集从用户空间拷贝到内核空间。此外,select 返回的文件描述符就绪状态只能通过线性扫描的方式逐个进行处理,对于大规模连接的情况下,效率非常低下。

2. poll

poll 是在 select 的基础上进行改进得到的。相比于 select,poll 的改进主要体现在两个方面:(1) poll 中的文件描述符状态集合是在内核空间中维护的,不需要每次都从用户空间拷贝;(2) poll 返回的文件描述符状态不再是线性扫描的方式,而是通过倒排索引方式。这样可以避免了 select 中需要逐个扫描的问题,提高了效率。poll 对文件描述符数量的限制和 select 类似,通常也是 1024。

poll 的优点:解决了 select 效率低下的问题,提高了效率。

poll 的缺点是:仍然需要遍历所有的文件描述符,当连接数量增多时,效率仍然不高。

3. epoll

epoll 是 Linux 专门为网络 I/O 设计的,相比于 select/poll,epoll 提供了更高效的 I/O 事件通知机制。epoll 的主要特点有:(1) 采用了回调机制,将就绪的事件放入一个事件就绪队列中,用户进程可以通过读取该队列来获取就绪的事件;(2) 采用事件驱动的方式,只需要管理少量的 epoll 对象,可以达到高效监控大规模的连接数;(3) epoll 对监控的文件描述符数量没有上限。

epoll 的优点是:高效,支持大规模并发连接。epoll 通过注册事件来关注感兴趣的文件描述符,只有当有事件发生时,才会通知用户进程,避免了无效的轮询。此外,epoll 还支持边缘触发和水平触发两种模式,边缘触发模式可以处理更多的事件,但也需要更多的系统资源。

epoll 的缺点是:Linux 特有的接口,不具有跨平台性。

总结:select/poll/epoll 是操作系统提供的 I/O 多路复用机制,用于同时监控多个文件描述符的状态。select 是最早出现的机制,采用线性扫描的方式,效率较低;poll 在 select 的基础上进行改进,采用倒排索引方式提高了效率;epoll 是 Linux 专门为网络 I/O 设计的,提供了高效的事件通知机制,支持大规模并发连接。