Skip to content

IO 多路复用

select/poll/epoll、水平与边缘触发、应用场景。

Updated View as Markdown
For humans

IO 多路复用

高并发网络服务的基石:一个线程同时监听大量连接。面试必考:select/poll/epoll 对比、触发模式。

解决什么

阻塞 IO: 一个线程等一个连接, 千连接千线程(线程爆炸)
IO 多路复用: 一个线程等所有连接, 有事件才处理

三兄弟对比

维度 select poll epoll
数据结构 位图(1024 上限) 链表(无上限) 事件表(内核维护)
每次调用 全量拷贝 fd 集合 全量拷贝 只传变化的
就绪通知 轮询扫描 轮询扫描 事件回调
复杂度 O(n) O(n) O(就绪数)
平台 通用 通用 Linux

epoll 的杀手锏

  1. 内核事件表:fd 注册一次,不用每次全量拷贝(select 每次都要)
  2. 事件驱动:就绪才通知(select/poll 要全扫)
  3. 百万连接只有少量活跃时,epoll 效率碾压

触发模式

模式 语义 注意
水平触发(LT) 有数据就持续通知 简单,不读完也会再通知(默认)
边缘触发(ET) 状态变化才通知一次 必须一次读完,否则丢数据
LT: 缓冲有 100 字节, 读 10 字节 → 还会通知(还有 90)
ET: 缓冲有 100 字节, 读 10 字节 → 不再通知(下次有新数据才通知)

ET 的坑:要循环读到 EAGAIN(读空),否则数据滞留。高并发框架用 ET + 非阻塞 IO 组合(如 Redis、Netty)。

应用

系统 用法
Redis 单线程事件循环(见 Redis 线程模型篇)
Nginx 事件驱动高并发
Node.js libuv 封装
Netty Java NIO 封装(见事件驱动篇)

与多线程的配合

  • 单线程 + 多路复用:IO 密集场景足够(Redis 十万 QPS)
  • 多线程 + 多路复用:每个线程有自己的 epoll(多核利用)
  • Reactor 模式是标准封装(见事件驱动篇)

面试追问

  1. epoll 为什么比 select 快? 内核事件表(不重复拷贝)+ 事件回调(不轮询)。就绪才通知
  2. 水平触发和边缘触发? LT 持续通知(默认),ET 只通知一次(要读完)。ET + 非阻塞是高性能组合
  3. select 的 1024 限制? fd 位图上限。poll 链表无上限但仍是轮询
  4. IO 多路复用解决什么? 单线程管海量连接:事件驱动,有事件才处理
  5. Redis 为什么用 epoll? 单线程 + 事件驱动:十万连接只有命令到达才处理
Navigation

Type to search…

↑↓ navigate↵ selectEsc close