I/O复用:select、poll、epoll

发布于:2025-06-21 ⋅ 阅读:(14) ⋅ 点赞:(0)

三组I/O复用函数的比较

这三种函数都通过某种结构体变量告诉内核该监听那些fd上的哪些事件,并用该结果提参数来获得内核处理结果。

select

事件集合

select没有将fd和事件进行绑定,通过三个参数分别传入可读、可写及异常等事件,告诉内核监听fd上的哪些事件。内核通过对这些参数的在线修改反馈其中的就绪事件,(不能同时处理更多事件类型,每次三个)所以每次调用select都要重穿参数

实现原理和工作效率

select使用轮询的方式,即每次调用都要扫描整个文件描述符集合fd_sets,所以算法时间复杂度为O(n)

工作模式

LT

最大支持文件描述符的个数(文件描述符集合的大小)

有限

poll

事件集合

每次传入用户感兴趣的事件(事件集,统一处理所有事件类型(内核同时监听fd上的感兴趣的所有事件类型)),内核通过修改pollfd.revents反馈就绪事件

实现原理和工作效率

poll使用轮询的方式,即每次调用都要扫描整个文件描述符集合,所以算法时间复杂度为O(n)

工作模式

LT

最大支持文件描述符的个数(文件描述符集合的大小)

65535

epoll

事件集合

内核通过一个事件表直接管理用户所有感兴趣的事件,所以每次调用无需反复传入用户感兴趣的事件。调用epoll_wait反馈就绪事件events

实现原理和工作效率

epoll是采用回调的方式,内核检测到就绪的fd触发回调,回调将就绪的事件插入事件就绪队列,内核在适当的时机将就绪队列拷贝到用户空间,算法复杂度O(1)

工作模式

ET/LT

最大支持文件描述符的个数(文件描述符集合的大小)

65535

#总结

对比项

select

poll

epoll

事件集合

通过三个参数分别传入可读、可写、异常事件,不绑定 fd 与事件,每次都要重新设置

每次传入统一事件集合,支持所有事件类型,通过 revents 反馈就绪事件

内核维护事件表,注册一次即可,无需重复传入,epoll_wait 反馈就绪事件

实现原理与效率

每次都要扫描整个 fd_set 集合,采用轮询,O(n)

每次都要遍历 pollfd 数组,采用轮询,O(n)

内核通过回调机制将就绪事件插入就绪队列,再拷贝到用户空间,O(1)

工作模式

水平触发(LT)

水平触发(LT)

支持水平触发(LT)和边缘触发(ET)

fd 与事件绑定

不绑定,每次调用都要重新设置

 绑定事件与 fd

内核注册后自动跟踪 fd 的状态

重复传参需求

 每次调用都需要重新设置 fd_set

 每次调用都需要重新设置 pollfd[]

只需首次注册,后续 epoll_wait() 等待结果即可

最大支持的文件描述符数

通常受限于 FD_SETSIZE,默认 1024

通常为 65535(理论值),由系统资源限制

通常为 65535(理论值),由内核资源限制

ET和LT

模式类型

通知机制

应用处理方式

是否需要非阻塞 I/O

特点与说明

LT(Level Trigger)

只要缓冲区有数据就会不断通知

可分多次读取

否(推荐使用)

容错性高,适合初学者,但效率略低

ET(Edge Trigger)

状态从“无”变为“有”时才通知一次

一次性读/写完或读空循环处理

必须使用

高效但易出错,必须配合非阻塞 I/O 否则可能“卡死”


网站公告

今日签到

点亮在社区的每一天
去签到