I/O 多路复用器(select、poll、epoll)与 Reactor 模式详解
I/O 多路复用器(select、poll、epoll)与 Reactor 模式详解
1. I/O 多路复用器(Multiplexer)
I/O 多路复用器允许一个线程同时监控多个文件描述符(fd),并在它们就绪时进行读写操作。常见的三种多路复用器是 select、poll、epoll。
特性 | select | poll | epoll |
---|---|---|---|
工作原理 | 轮询所有 fd | 轮询所有 fd | 事件驱动(回调) |
最大 fd 数量 | 1024(固定) | 无限制(系统资源限制) | 无限制(系统资源限制) |
效率 | O(n),遍历所有 fd | O(n),遍历所有 fd | O(1),仅处理就绪 fd |
适用场景 | fd 数量少且活跃度高 | fd 数量较多但活跃度一般 | fd 数量大且活跃度低 |
内存拷贝 | 每次调用需拷贝 fd 集合 | 每次调用需拷贝 fd 数组 | 仅注册一次,无额外拷贝 |
触发模式 | 水平触发(LT) | 水平触发(LT) | 支持水平触发(LT)和边缘触发(ET) |
总结:
- select:适用于 fd 数量少(≤1024)且活跃比例高的场景,如小型服务器。
- poll:适用于 fd 数量较多但活跃比例一般的场景,相比 select 无数量限制。
- epoll:适用于高并发场景(fd 数量大且活跃比例低),如 Nginx、Redis。
2. Reactor 模式
Reactor 模式是一种 事件驱动 的设计模式,用于高效处理大量并发 I/O 请求。它基于 I/O 多路复用器(如 epoll)实现,核心思想是 “事件分发 + 回调”。
Reactor 的核心组件:
- Reactor(反应器):
- 负责监听 I/O 事件(如
epoll_wait
)。 - 当事件就绪时,分发给对应的处理器(Handler)。
- 负责监听 I/O 事件(如
- Handler(事件处理器):
- 处理具体的事件(如
accept
、read
、write
)。 - 通常以回调函数的形式注册到 Reactor 中。
- 处理具体的事件(如
- Demultiplexer(多路复用器):
- 底层使用
select
/poll
/epoll
监听 fd 状态。 - 当 fd 就绪时,通知 Reactor。
- 底层使用
Reactor 的工作流程:
- 注册事件处理器:
- 应用程序向 Reactor 注册 fd 及其对应的事件处理器(Handler)。
- 例如:监听 socket 注册
EPOLLIN
事件,回调accept_handler
。
- 事件循环(Event Loop):
- Reactor 调用
epoll_wait
等待事件发生。 - 当某个 fd 就绪时,Reactor 根据事件类型调用对应的 Handler。
- Reactor 调用
- 处理事件:
- Handler 执行具体的业务逻辑(如读取数据、发送响应)。
- 处理完成后,可以继续注册新的事件(如
EPOLLOUT
写事件)。
Reactor 的优点:
- 单线程高并发:一个线程可以处理成千上万的连接。
- 低资源消耗:避免多线程的上下文切换开销。
- 事件驱动:只处理就绪的 fd,不浪费 CPU 时间。
Reactor 的缺点:
- 编程复杂度高:需要管理回调函数和事件状态。
- 不适合 CPU 密集型任务:长时间的计算会阻塞事件循环。
3. Reactor 与多路复用器的关系
- Reactor 是模式,epoll 是实现:
- Reactor 是一种设计模式,定义了事件分发和处理的框架。
epoll
是 Linux 提供的 I/O 多路复用机制,用于实现 Reactor 的事件监听部分。
- Reactor 可以基于不同的多路复用器:
- 可以用
select
、poll
或epoll
作为 Reactor 的底层 Demultiplexer。 - 但
epoll
是最适合 Reactor 的高性能实现,因为它的事件驱动机制与 Reactor 完美契合。
- 可以用
示例:Reactor + epoll 的工作流程
4. 总结
概念 | 作用 | 适用场景 |
---|---|---|
select | 轮询所有 fd,简单但效率低 | fd 数量少(≤1024),活跃度高 |
poll | 改进版 select,无数量限制 | fd 数量较多,活跃度一般 |
epoll | 事件驱动,高效处理高并发 | fd 数量大(>1024),活跃度低 |
Reactor | 事件驱动框架,基于多路复用器 | 高并发服务器(Nginx、Redis) |
结论:
- 小型服务器(连接数少):
select
或poll
足够。 - 高并发服务器(连接数多):
epoll + Reactor
是最佳选择。 - Reactor 模式 的核心是 事件驱动 + 回调,
epoll
是其最佳搭档。