select、poll、epoll是Python中I/O多路复用机制:select跨平台但受限于1024fd且O(n)开销;poll突破数量限制但仍O(n)扫描;epoll为Linux专属,事件驱动、O(1)就绪通知、支持ET/LT模式。

Python 中的 select、poll 和 epoll 都是 I/O 多路复用机制,用于同时监控多个文件描述符(如 socket)的就绪状态,但它们底层实现、性能表现和适用平台差异明显。
select:跨平台但有局限
select 是最老、最通用的接口,所有主流操作系统都支持。它通过三个位图(read_fds、write_fds、except_fds)传入待监控的 fd 集合,内核遍历全部 fd 判断是否就绪。缺点明显:
- 单次调用最大监控 fd 数受限(通常是 1024,由 FD_SETSIZE 宏决定)
- 每次调用都要把整个 fd 集合从用户态拷贝到内核态,开销随 fd 数线性增长
- 返回后需遍历所有传入的 fd 才能知道哪些就绪,效率低
- 无法告知具体事件类型(如 EPOLLIN/EPOLLOUT),只能靠轮询判断可读/可写
poll:突破数量限制,仍需线性扫描
poll 使用结构体数组(struct pollfd)替代位图,因此没有固定 fd 数量上限(只受系统资源限制)。但它依然存在本质缺陷:
- 每次调用仍需将整个数组拷贝进内核
- 内核仍需线性扫描全部 fd 判断就绪状态
- 返回后仍需遍历数组检查
revents字段才能获知事件类型 - 在 Linux 上,
poll实际是基于epoll的兼容封装,但 Python 的select.poll()默认走传统 poll 路径
epoll:Linux 专属高性能方案
epoll 是 Linux 2.6+ 提供的高效 I/O 多路复用接口,核心设计是「事件驱动 + 就绪列表」:
立即学习“Python免费学习笔记(深入)”;
- 通过
epoll_create()创建一个内核事件表,后续用epoll_ctl()增删改监控项,避免重复传 fd 集合 -
epoll_wait()返回的是**已就绪的 fd 列表**,无需遍历全部监控项 - 支持边缘触发(ET)和水平触发(LT)模式,ET 模式配合非阻塞 I/O 可减少事件重复通知
- 时间复杂度接近 O(1)(就绪事件数),而非 O(n)(总监控 fd 数)
- Python 的
select.epoll()直接封装 Linux epoll 系统调用,仅限 Linux 使用
Python 中的实际选择建议
在 Python 标准库中,这些接口统一暴露在 select 模块下,但使用逻辑不同:
- 写跨平台网络程序(如兼容 macOS/Windows),优先用
select.select()或更高级的asyncio(其底层会按平台自动选select/poll/kqueue/epoll) - Linux 服务器上追求高并发(如 tens of thousands 连接),应直接用
select.epoll(),或使用基于它的框架(如 Tornado、Gunicorn 的 async worker) -
select.poll()在 Linux 上性能不如epoll,在其他系统上可能是唯一优于select的选项,但实际应用较少 - 现代 Python 开发中,绝大多数场景推荐用
asyncio,它屏蔽了底层差异,且默认启用最优机制










