C++(6) select/poll/epoll
六、IO 多路复用select/poll/epollIO 多路复用让一个进程 / 线程同时监控多个文件描述符socket、文件当某个文件描述符就绪可读 / 可写 / 异常时再进行 IO 操作解决 C10K 问题核心有三种实现1. select数据结构fd_set位图存储待监控的文件描述符大小受限于FD_SETSIZE通常 1024工作流程用户将fd_set从用户空间拷贝到内核空间内核遍历所有文件描述符检查是否就绪内核将就绪的文件描述符置位拷贝回用户空间返回就绪数量用户遍历fd_set确定具体就绪的文件描述符。缺点文件描述符数量受限默认 1024每次调用需遍历所有 fd时间复杂度 O (n)每次调用需拷贝fd_set到内核空间开销大fd_set被内核修改下次调用前需重新初始化。2. poll数据结构struct pollfd结构体数组由用户动态管理大小无文件描述符数量限制工作流程与 select 类似区别在于pollfd的events表示监控事件revents表示就绪事件分离了输入和输出无需重新初始化。优点无文件描述符数量限制无需重新初始化参数缺点仍需遍历所有 fd时间复杂度 O (n)每次调用需拷贝结构体数组到内核空间开销大。3. epollLinux 特有推荐数据结构红黑树存储所有待监控的文件描述符支持高效的增删改查就绪链表存储就绪的文件描述符内核主动将就绪 fd 加入链表无需遍历工作流程调用epoll_create()创建 epoll 实例返回 epfd调用epoll_ctl()将 fd 添加到红黑树中指定监控事件仅拷贝一次到内核调用epoll_wait()等待就绪事件内核直接返回就绪链表时间复杂度 O (1)优点无文件描述符数量限制仅受内存限制事件驱动无需遍历所有 fd效率高fd 仅拷贝一次到内核开销小支持 **LT水平触发和ET边缘触发** 两种模式ET 模式更高效仅通知一次就绪。LT vs ETLTfd 就绪后若未处理完epoll_wait()会持续通知直到处理完成容错性高ETfd 就绪后仅通知一次需一次性处理完所有数据效率高要求非阻塞 IO。4. 三者对比表格特性selectpollepoll数据结构位图fd_set结构体数组pollfd红黑树 就绪链表fd 数量限制有FD_SETSIZE1024无动态数组无受内存限制时间复杂度O(n)O(n)O(1)内核 / 用户空间拷贝每次调用都拷贝每次调用都拷贝仅拷贝一次epoll_ctl参数重用需重新初始化无需重新初始化无需重新初始化触发模式仅 LT仅 LTLT/ET适用场景连接数少且固定连接数中等连接数多高并发如百万连接