1. 简介
select、poll 和 epoll 都是用于 I/O 多路复用的机制,它们的目的都是监视多个文件描述符,以确定是否有数据可读、可写或者发生了异常。
2. select
- select 是最古老的 I/O 多路复用机制之一,在 Unix 系统中使用较为广泛。
- select 使用一个位图来存储文件描述符,监视的文件描述符数量有限制,通常是 1024 个(可以通过修改文件描述符限制来提高数量,但仍受限制)。
- select 每次调用时都需要将待监视的文件描述符集合从用户态拷贝到内核态,这会导致性能开销随着文件描述符数量的增加而增加。
- select 对监视的文件描述符集合的扫描是线性的,随着文件描述符数量的增加,性能下降明显。
3. poll
- poll 是对 select 的改进,使用了链表结构来存储文件描述符,因此没有文件描述符数量的限制。
- 与 select 类似,poll 每次调用时需要将待监视的文件描述符集合从用户态拷贝到内核态,但性能上相对于 select 有所提升。
- poll 的主要缺点是,随着文件描述符数量的增加,性能会逐渐下降,因为 poll 仍然是线性扫描文件描述符集合。
4. epoll
- epoll 是 Linux 下的一种高性能 I/O 多路复用机制,相比于 select 和 poll,epoll 的性能更好。
- epoll 使用了事件驱动的方式,不需要每次调用时将待监视的文件描述符集合从用户态拷贝到内核态,而是采用了基于回调的方式,当文件描述符就绪时,内核直接通知应用程序。
- epoll 支持三种工作模式:EPOLLIN(可读)、EPOLLOUT(可写)、EPOLLET(边缘触发模式),可以更加灵活地满足不同的需求。
- epoll 对于大量文件描述符的管理具有更好的性能和扩展性,不会因为文件描述符数量的增加而导致性能下降。
4.1 触发模式
在 epoll 中,有两种触发模式可以选择:水平触发(Level-Triggered,简称 LT)和边缘触发(Edge-Triggered,简称 ET)。这两种触发模式在处理文件描述符就绪事件时有所不同:
1.水平触发(LT)
- 在水平触发模式下,当文件描述符就绪时,epoll_wait 函数会立即返回,并且会返回所有处于就绪状态的文件描述符。
- 如果应用程序没有处理完所有就绪事件,并且该文件描述符上的事件状态没有改变,下一次调用 epoll_wait 时,该文件描述符仍然会被返回。
- 水平触发模式是 epoll 的默认触发模式。
2.边缘触发(ET)
- 在边缘触发模式下,当文件描述符就绪时,epoll_wait 函数只会返回一次,并且只返回该文件描述符上自上次 epoll_wait 调用后发生的就绪事件。
- 如果应用程序没有处理完所有就绪事件,并且该文件描述符上的事件状态没有改变,下一次调用 epoll_wait 时,该文件描述符不会再次被返回,除非有新的就绪事件发生。
- 边缘触发模式要求应用程序对文件描述符的就绪事件立即进行处理,否则可能会错过事件。