IO多路复用

发布于:2025-08-29 ⋅ 阅读:(13) ⋅ 点赞:(0)
  • IO多路复用
    • 对多个文件描述符的读写可以复用一个进程
    • 在不创建新的进程线程的前提下,使用一个进程实现对多个文件读写的同时监测

    • select、poll、epoll
      • select的优缺点
        • 优点:
          • 跨平台:几乎所有Unix-like系统都支持
          • 简单易用:API相对简单,易于理解
          • 超时控制:可以设置精确的超时时间
        • 缺点:
          • 性能问题:每次调用都需要遍历描述符
          • 描述符限制:使用位图实现对文件描述符集合的保存,最多允许同时监测1024个文件描述符
          • 内存拷贝:每次调用都需要应用和内核层的反复数据(文件描述符集合表)拷贝
          • 工作受限:只能工作在水平触发模式(低速模式),不能工作在边沿触发模式(高速模式
      • poll的优缺点
        • 优点:
          • 无描述符数量限制:用链表实现对衷件描述符集合的保存,没有了监测的文件描述符上限限制
          • 更高效的事件检查:不需要每次重新设置整个集合
          • 更丰富的事件类型:支持更多种类的事件标志
          • 更简单的API:不需要计算最大文件描述符
        • 缺点:
          • 性能问题:仍然需要遍历所有描述符:和select一样是O(n)复杂度
          • 平台兼容性:虽然广泛支持,但不如select普遍
          • 性能不如epoll:在大规模并发场景下性能较差
          • 需要手动管理数组:需要自己处理数组的添加、删除和压缩
      • epoll的优缺点
        • 优点:
          • 无描述符数量限制:使用红黑树(二叉树)实现文件描述符集合的存储,没有文件描述符上限限制,提高查找效率
          • 内存效率:将文件描述符集合创建在内核层,避免了应用层和内核层的反复数据拷贝
          • 高性能:返回的是到达事件,只处理活跃的描述符,时间复杂度O(1)
          • 边缘出发模式:可工作在水平触发模式(低速模式),也可工作在边沿触发模式(高速模式)
        • 缺点:
          • Linux特有:不具备跨平台性
          • 编程复杂度:边缘触发模式需要更仔细的处理
          • 需要非阻塞IO:最佳性能需要配合非阻塞IO
          • 学习曲线:比select/poll更复杂
      • 性能对比

  • select实现IO多路复用
    • 创建文件描述符集合
    • 添加关注的文件描述符到集合
    • 使用select传递集合表给内核,内核开始监测事件
    • 当内核监测到事件时,应用层select将解除阻塞,并获得相关的事件结果
    • 根据select返回的结果做不同的情况处理
  • 函数接口
    • void FD_CLR(int fd, fd_set *set); 从集合中移除描述符
    • int FD_ISSET(int fd,fd_set *set); 检查描述符是否在集合中
    • void FD_SET(int fd, fd_set *set); 添加描述符到集合
    • void FD_ZERO(fd_set *set) 清空集合
    • select :int select(int nfds,fd_set*readfds,fd_set *writefdsfd_set *exceptfds, struct timeval *timeout)
      • 功能:传递文件描述符结合表给内核并等待获取事件结果
      • 参数:
        • nfds:关注的最大文件描述符+1;
        • readfds:读事件的文件描述符集合;
        • writefds:写事件的文件描述符集合;
        • exceptfds:其他事件的文件描述符集合;
        • timeout:设置select监测时的超时时间;NULL:不设置超时时间(select一直阻塞等待)
      • 返回值:成功:返回内核监测的到达事件的个数;失败:-1;0:超时时间到达,但没有事件发生,则返回0
  • epoll实现IO多路复用
    • 创建文件描述符结合;epoll_create
    • 添加关注的文件描述符;epoll_ctl
    • epoll通知内核开始进行事件监测;epoll_wait
    • epoll返回时,获取到到达事件的结果
    • 根据到达事件做任务处理
  • 函数接口
    • int epoll_create(int size);
      • 功能:通知内核创建文件描述符集合
      • 参数:size:监测的文件描述符个数
      • 返回值:成功:文件描述符(代表内核创建的集合);失败:-1
    • int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
      • 功能:对epoll的文件描述符集合进行操作
      • 参数:
        • epfd:创建的epoll集合
        • op:对文件描述符集合进行的操作
          • EPOLL_CTL_ADD:添加文件描述符到集合
          • EPOLL_CTL_MOD:修改集合中的文件描述符
          • EPOLL_CTL_DEL:删除集合中的文件描述符
        • fd:要操作的文件描述符
        • event:文件描述符对应的事件
        • events:文件描述符的事件
        • data.fd:关注的文件描述符
      • 返回值:成功:0;失败-1
    • int epoll_wait(int epfd, struct epoll_event *events,int maxevents,int timeout)
      • 功能:通知内核开始监测文件描述符的事件
      • 参数:
        • epfd:监测的文件描述符集合
        • events:保存返回的到达事件结果(数组)
          • struct epoll_event evs[MAX_FD_CNT]
        • maxevents:最大的事件个数
        • timeout:监测的超时时间;-1:不设置超时(一直阻塞)
      • 返回值:成功:到达的事件的个数;失败:-1

网站公告

今日签到

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