高并发编程必备知识IO多路复用技术select、poll、epoll讲解

本文详细介绍了I/O多路复用技术,包括select、poll和epoll的基本原理及优缺点。select存在文件描述符限制,poll虽无限制但效率低,而epoll通过回调机制和高效的数据结构解决了这些问题,提供更高的性能。epoll在处理大量连接时,如100万个连接中只有1万个活跃,其优势尤为明显,避免了轮询和大量的状态检查,降低了系统开销。
什么是IO多路复用:I/O多路复用,I/O是指网络I/O, 多路指多个TCP连接(即socket或者channel),复用指复用一个或几个线程。简单来说:就是使用一个或者几个线程处理多个TCP连接,最大优势是减少系统开销小,不必创建过多的进程/线程,也不必维护这些进程/线程
select:
    基本原理:监视文件3类描述符: writefds、readfds、和exceptfds,调用后select函数会阻塞住,等有数据 可读、可写、出异常 或者 超时 就会返回, select函数正常返回后,通过遍历fdset整个数组才能发现哪些句柄发生了事件,来找到就绪的描述符fd,然后进行对应的IO操作,几乎在所有的平台上支持,跨平台支持性好 
缺点:
    1)select采用轮询的方式扫描文件描述符,全部扫描,随着文件描述符FD数量增多而性能下降
    2)每次调用 select(),需要把 fd 集合从用户态拷贝到内核态,并进行遍历(消息传递都是从内核到用户空间)
    3)最大的缺陷就是单个进程打开的FD有限制,默认是1024   (可修改宏定义,但是效率仍然慢)                
    static final  int MAX_FD = 1024
poll:
    基本流程:
 select() 和 poll() 系统调用的大体一样,处理多个描述符也是使用轮询的方式,根据描述符的状态进行处理,一样需要把 fd 集合从用户态拷贝到内核态,并进行遍历。最大区别是: poll没有最大文件描述符限制(使用链表的方式存储fd)
epoll 基本原理:
      在2.6内核中提出的,对比select和poll,epoll更加灵活,没有描述符限制,用户态拷贝到内核态只需要一次
      使用事件通知,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用callback的回调机制来激活对应的fd
    
      优点:
          1)没fd这个限制,所支持的FD上限是操作系统的最大文件句柄数,1G内存大概支持10万个句柄 
          2)效率提高,使用回调通知而不是轮询的方式,不会随着FD数目的增加效率下降
          3)通过callback机制通知,内核和用户空间mmap同一块内存实现
   
          Linux内核核心函数
          1)epoll_create()  在Linux内核里面申请一个文件系统 B+树,返回epoll对象,也是一个fd
          2)epoll_ctl() 操作epoll对象,在这个对象里面修改添加删除对应的链接fd, 绑定一个callback函数
          3)epoll_wait()  判断并完成对应的IO操作
   
      缺点:
          编程模型比select/poll 复杂
          例子:100万个连接,里面有1万个连接是活跃,在 select、poll、epoll分别是怎样的表现                
          select:不修改宏定义,则需要 1000个进程才可以支持 100万连接
          poll:100万个链接,遍历都响应不过来了,还有空间的拷贝消耗大量的资源
          epoll: 无文件连接符的限制,采用回调函数的机制处理相应的fd,不需要遍历循环fdset数组,效率较高。

### 异步IO多路复用selectpollepoll的区别 #### Select机制分析 Select采用的是轮询的方式去检测每一个文件描述符的状态变化,当调用`select()`时,它会阻塞直到有一个或多个文件描述符准备好进行读取或写入操作,或者是超时发生。然而,在每次调用之前都需要重新设置感兴趣的文件描述符集合,并且对于大量连接来说效率较低,因为其内部实现是对所有传入的文件描述符依次做线性扫描。 #### Poll机制解析 PollSelect相似之处在于两者都基于水平触发模式工作,这意味着只要某个文件描述符处于可读状态,则一直保持激活直至被消费掉为止。但是poll解决了select的最大文件描述符数量受限于FD_SETSIZE的问题,理论上支持更大的并发量。不过poll同样存在性能瓶颈—随着监控列表的增长,遍历整个数组查找已准备好的事件仍然是一项耗时的工作[^4]。 #### Epoll特性介绍 Epoll则采用了完全不同的设计理念来优化上述两种方式存在的缺陷: - **边缘触发(Edge Triggered, ET) vs 水平触发(Level Triggered, LT)**: 支持这两种模式,默认情况下为LT模式下运作。ET模式仅在监测到新的数据到来瞬间触发一次回调通知给应用层;而在LT模式里只要有未处理的数据就会持续报告。 - **高效的通知机制**: 不同于前两者的被动查询模型,epoll主动告知哪些具体的socket已经发生了特定类型的活动,从而使得开发者能够精准定位并响应感兴趣的变化源而不必逐一排查全部可能的对象。 - **高性能扩展能力**: 利用了Linux内核提供的红黑树结构以及hash表技术实现了高效的动态增删改查功能,这不仅提高了系统的吞吐率还降低了CPU占用率。此外,由于只关心活跃链接所以即使面对海量级的同时在线用户也能维持良好的表现力[^1]。 ```c int epoll_fd = epoll_create(EPOLL_SIZE); struct epoll_event event; event.events = EPOLLIN | EPOLLET; // 设置为边沿触发 event.data.fd = listen_sock; // 注册监听套接字至epoll实例中 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_sock, &event) == -1){ perror("epoll set insertion error"); } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值