Appearance
I/O 多路复用
I/O 多路复用让一个线程等待多个文件描述符(socket、管道等)的就绪事件;有事件时再处理相应 I/O。它适合大量连接但每个连接大部分时间空闲的网络服务器。
“就绪”通常表示读/写操作可能不阻塞,不等于一定读到完整应用消息。非阻塞 I/O、缓冲区和协议解析仍不可少。
select、poll、epoll 对比
| 特性 | select | poll | epoll(Linux) |
|---|---|---|---|
| 监听集合 | 位图 fd_set | pollfd 数组 | 内核维护兴趣集合 |
| FD 数量 | 常有 FD_SETSIZE 上限 | 无 fd_set 固定上限 | 受系统资源限制 |
| 每次调用 | 用户态传入并扫描整个集合;结果也需扫描 | 用户态传入并扫描整个数组 | epoll_ctl 注册/修改;epoll_wait 返回就绪事件 |
| 大量空闲连接 | 扫描成本 O(n) | 扫描成本 O(n) | 通常更适合,返回活跃事件 |
| 可移植性 | POSIX,广泛支持 | POSIX,广泛支持 | Linux 特有 |
epoll 的优势不意味着所有负载下都必然更快:连接少、绝大部分连接都很活跃或事件处理成本主导时,差异可能不明显。
epoll 使用要点
- 创建
epoll实例; - 把监听 socket 和连接 socket 通过
epoll_ctl注册EPOLLIN、EPOLLOUT等兴趣事件; - 用
epoll_wait阻塞等待就绪事件; - 对返回事件执行 accept/read/write,并维护每个连接的状态机和缓冲区。
LT 与 ET
- 水平触发(LT):只要 FD 仍可读/可写就持续通知,使用简单,是默认模式。
- 边缘触发(ET):仅在状态从未就绪变为就绪时通知,减少重复通知;一般必须配合非阻塞 FD,并循环读/写直到返回
EAGAIN,否则可能遗漏后续处理机会。
epoll 是就绪通知机制,不是“自动回调框架”;程序仍需正确处理部分读写、连接关闭、错误、背压和任务调度。
适用边界
I/O 多路复用解决的是等待大量 I/O 的问题。若单个请求包含 CPU 密集计算,应交给线程池、进程池或异步任务系统,避免阻塞事件循环。跨平台可选 kqueue(BSD/macOS)、IOCP(Windows)或封装库(如 libuv、Asio)。