linux下I/O复用与epoll实际使用(一)

这篇博客介绍了Linux下I/O复用机制中的epoll,对比了select和poll的局限性,详细阐述了epoll的高效奥秘,包括使用mmap、红黑树和链表等数据结构。epoll通过epoll_create、epoll_ctl和epoll_wait三个方法实现高效I/O操作,特别适合连接数量多但活动连接少的场景。文章还讨论了EPOLLONESHOT和LT/ET模式的应用,强调了正确使用epoll的重要性。
摘要由CSDN通过智能技术生成

一、背景

I/O多路复用有很多种实现,在linux上,2.4内核前主要是select和poll,从2.6内核正式引入epoll以来。epoll已经成为目前实现高性能网络服务器的必备技术。尽管他们的使用方法不尽相同,但是从本质上却没有什么区别。

二、选择epoll的原因

select的缺陷
高并发的核心解决方案是1个线程处理所有连接的“等待消息准备好”,这一点上epoll和select是无争议的。但select在数十万并发连接存在时,可能每一毫秒只有数百个活跃的连接,同时其余数十万连接在这一毫秒是非活跃的,select的使用方法是这样的:
返回的活跃连接==select(全部待监控的连接)。
什么时候会调用select方法呢?在你认为需要找出有报文到达的活跃连接时,就应该调用。所以,调用,调用select在高并发时是会被频繁调用的。这样,这个频繁调用的方法,就很有必要看看它是否有效率,因为,它的的轻微效率损失都会被“频繁”二字放大。它有效率损失吗?显而易见,全部带监控是数以十万计的,返回的知识数百个活跃连接,这本身就是无效率的表现。被放大后就会发现,处理并发上万个连接时,select就完全力不从心了。
此外,在linux内核中,select所用的FD_SET时有限的,即内个中有个参数__FD_SETSIZE定义了每个FD_SET的句柄个数

/linux/posix_types.h:
#define __FD_SETSIZE         1024

其次,内核中实现select是用轮训方法,即每次检测都会遍历所有FD_SET中的句柄,显然,select函数执行时间与FD_SET中的句柄个数有一个比例关系,即select要检测的句柄数越多就会越耗时间。而poll和select的内部机制方面并没有太大的差异。相比于select机制,poll取消了最大监控文件描述符数量的限制。但没有从根本上解决大并发情况下耗时严重的问题。

主流I/O复用机制的benchmark

三、epoll高效的奥秘
epoll精巧的使用了三个方法来实现select做的事:
1、新建epoll描述符epoll_create()
2、epoll_ctl(epoll描述符,添加或者删除所有待监控的的连接)
3、返回的活跃连接
epoll_wait(epoll描述符)
与select对比,epoll分清了频繁调用和不频繁调用的操作,例如,epoll_ctl是不太频繁调用的,而epoll_wait是非常频繁调用的。这时,epoll_wait却几乎没有入参,这笔select的效率高出一大截,而且,它也不会随着并发连接的增加使得入参越发多起来,导致内核执行效率的下降。
要想深刻理解epoll,首先得了解epoll的三大关键要素:mmap、红黑树、链表。
epoll是通过内核与用户控件mmap同一块内存实现的。mmap将用户空间的一块内存同时衍射到相同的一块物理内存地址(不管是用户空间还是内核空间都是虚拟地址,最终要通过地址映射映射到物理地址),使得这块物理内存对内核和对用户均可见,减少用户态和内核态之间的数据转换。内核可以直接看到epoll监听的句柄,效率高。
红黑树将存储epoll所监听的套接字。上面mmap出来的内存如何保存epoll所监听的套接字,必然也得有一套数据结构,epoll在实现上采用红黑树去存储所有套接字,当添加或者删除一个套接字时(epoll_ctl),都在红黑树上去处理,红黑树本身插入和删除性能比较好,时间复杂度O(logN)。
红黑树数据结构
下面几个关键数据结构的定义

1 struct epitem
 2 {
 3     struct rb_node rbn;            //用于主结构管理的红黑树
 4     struct list_head rdllink;       //事件就绪队列
 5     struct epitem *next;           //用于主结构体中的链表
 6     struct epoll_filefd ffd;         //每个fd生成的一个结构
 7     int nwait;                 
 8     struct list_head pwqlist;     //poll等待队列
 9     struct eventpoll *ep;          //该项属于哪个主结构体
10     struct list_head fllink;        
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值