I/O多路转接之【epoll】

epoll

在Linux中,还提供了第三种I/O多路转接的方式,那就是epoll,它几乎具备了select和poll的全部优点,是公认的Linux2.6下的最好的多路I/O就绪通知方法。
先来看一下接口,再根据参数解释epoll的工作原理。epoll将多路转接拆分为三个步骤。
第一步:创建一个epoll语柄
这里写图片描述
这个函数用来创建一个epoll语柄,其中size一般被忽略,返回值是一个文件描述符,所以必须要用close关闭。
第二步,注册epoll事件函数
这里写图片描述
第一个参数是epoll_create返回的epoll语柄,在那一个语柄上进行操作,op是具体执行的操作,取值为三个宏,EPOLL_CTL_ADD表示注册fd到epfd中,EPOLL_CETL_MOD表示修改注册的监听事件,EPOLL_CTL_DEL表示从中删除一个fd,fd就是具体要执行的那一个fd。
来看一看epoll_event这个结构体。
这里写图片描述
其中events的表示关心的文件描述符上的什么事件,用宏表示,和poll的参数基本一致。data一般使用fd。
第三步:等待收集在这个epoll监控事件中已经发生的事情。
这里写图片描述
在这里events是一个已经分配好的epoll_event的数组,内核会把已经就绪的fd,按顺序放入到这个数组中,相当于read的一个缓冲区。
maxevents是告诉内核这个缓冲区有多大。timeout是超时时间,0是超时返回,-1表示永久阻塞。


epoll工作原理

在调用epoll_create()的时候,操作系统在内核中干了三件事情,首先创建一个空的红黑树。红黑树中的一个个节点就是要关心的文件描述符的事件,因此重复插入的元素就可以通过红黑树高效率的识别出来。
第二步会建立一个回调机制,所有注册的这个epoll中的事件都会与网卡驱动设备进行一个回调机制,也就是说当有事件发生的时候,就会回调这个方法。
第三步:建立一个就绪队列,当底层有事件发生的时候,就会把就绪的事件插入到就绪队列中,我们的用户只需要关心队列是否为空就行了。
这里写图片描述
所以总结epoll的使用原理:
1.使用epoll_create()来创建一个epoll语柄。
2.往这个epoll语柄中注册添加要监控的文件描述符。
3.等待文件描述符的就绪。


epoll的优缺点

优点:
1.epoll监控的文件描述符没有上限,并且底层使用红黑树进行管理,高效。
2.epoll是基于事件通知的:一旦底层有事件就绪,那么就会调用回调机制,这样随着文件描述符的增加,不需要像select,poll那样轮询的遍历是否就绪,即使文件描述符数量增多,也不会影响性能。
3.当事件就绪时,内核就会将其放到一个就绪队列中,因此我们调用epoll_wait获取文件描述符的时候,只需要到就绪队列中取就行,时间复杂度为O(1).
4.内存映射:这一点虽然网上都是说,但是是不对的。根据我的开发经验,
第一,操作系统不信任任何热,绝不会把自己的内核数据暴露给用户,第二,在epoll_wait的时候,我们需要自己手动传一个缓冲区。


epoll的两中触发方式

水平触发LT
epoll的默认工作方式就是工作在LT模式下的,LT模式的特点是,当底层有数据就绪的狮虎,就会一直向上层的应用程序发送通知消息,而上层在处理数据的时候,可以只处理一部分数据,过一会儿再处理剩下的。
边沿触发ET
而ET模式下,只有当数据从无变有,从少变多的这种变化的时候,才通知上层应用。因此,ET模式下,对开发人员的要求就必须要一次性把所有底层数据拿完,因此我们需要循环的方法读取底层数据,直至读出错。而且读取的文件必须设置成非阻塞式的,因为如果文件描述符非阻塞式的,那么read读完数据,对端并没有关闭写端,那么就会在read除阻塞,影响后续逻辑。


epoll中的惊群问题

惊群问题,就是当多个进程,多个线程在等待一个资源就绪的时候,一旦一个资源可用,就会造成多个进程,线程来竞争资源的现象。但是,只有一个进程/线程获取到这个资源,会造成系统对用户进程/线程频繁的做无效的调度,上下文切换,使得性能大大折扣。
在linux2.6之前,我们可以使用互斥锁来解决这个问题。
在linux2.6之后,通过引入一个标志位来解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值