Skip to content

I/O 多路复用

I/O 多路复用让一个线程等待多个文件描述符(socket、管道等)的就绪事件;有事件时再处理相应 I/O。它适合大量连接但每个连接大部分时间空闲的网络服务器。

“就绪”通常表示读/写操作可能不阻塞,不等于一定读到完整应用消息。非阻塞 I/O、缓冲区和协议解析仍不可少。

select、poll、epoll 对比

特性selectpollepoll(Linux)
监听集合位图 fd_setpollfd 数组内核维护兴趣集合
FD 数量常有 FD_SETSIZE 上限fd_set 固定上限受系统资源限制
每次调用用户态传入并扫描整个集合;结果也需扫描用户态传入并扫描整个数组epoll_ctl 注册/修改;epoll_wait 返回就绪事件
大量空闲连接扫描成本 O(n)扫描成本 O(n)通常更适合,返回活跃事件
可移植性POSIX,广泛支持POSIX,广泛支持Linux 特有

epoll 的优势不意味着所有负载下都必然更快:连接少、绝大部分连接都很活跃或事件处理成本主导时,差异可能不明显。

epoll 使用要点

  1. 创建 epoll 实例;
  2. 把监听 socket 和连接 socket 通过 epoll_ctl 注册 EPOLLINEPOLLOUT 等兴趣事件;
  3. epoll_wait 阻塞等待就绪事件;
  4. 对返回事件执行 accept/read/write,并维护每个连接的状态机和缓冲区。

LT 与 ET

  • 水平触发(LT):只要 FD 仍可读/可写就持续通知,使用简单,是默认模式。
  • 边缘触发(ET):仅在状态从未就绪变为就绪时通知,减少重复通知;一般必须配合非阻塞 FD,并循环读/写直到返回 EAGAIN,否则可能遗漏后续处理机会。

epoll 是就绪通知机制,不是“自动回调框架”;程序仍需正确处理部分读写、连接关闭、错误、背压和任务调度。

适用边界

I/O 多路复用解决的是等待大量 I/O 的问题。若单个请求包含 CPU 密集计算,应交给线程池、进程池或异步任务系统,避免阻塞事件循环。跨平台可选 kqueue(BSD/macOS)、IOCP(Windows)或封装库(如 libuv、Asio)。

使用 Markdown 与 VitePress 构建