Poll,Select和Epoll实现原理和性能对比



Poll和Select和Epoll都是事件触发机制,当等待的事件发生就触发进行处理,多用于Linux实现的服务器对客户端连接的处理。

Poll和Select都是这样的机制:可以阻塞地同时探测一组支持非阻塞的IO设备,是否有事件发生(如可读,可写,有高优先级的错误输出,出现错误等等),直至某一个设备触发了事件或者超过了指定的等待时间——也就是它们的职责不是做IO,而是帮助调用者寻找当前就绪的设备。

原文链接:http://blog.chinaunix.NET/uid-20792262-id-2909919.html


int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);



 epoll相关系统调用是在Linux 2.5.44开始引入的。该系统调用针对传统的select/poll系统调用的不足,设计上作了很大的改动。select/poll的缺点在于:
    1.每次调用时要重复地从用户态读入参数。
    2.每次调用时要重复地扫描文件描述符。
    3.每次在调用开始时,要把当前进程放入各个文件描述符的等待队列。在调用结束后,又把进程从各个等待队列中删除。
    在实际应用中,select/poll监视的文件描述符可能会非常多,如果每次只是返回一小部分,那么,这种情况下select/poll显得不够高效。 epoll的设计思路,是把select/poll单个的操作拆分为1个epoll_create+多个epoll_ctrl+一个wait。此外,内核针对epoll操作添加了一个文件系统”eventpollfs”,每一个或者多个要监视的文件描述符都有一个对应的eventpollfs文件系统的inode节点,主要信息保存在eventpoll结构体中。而被监视的文件的重要信息则保存在epitem结构体中。所以他们是一对多的关系。
   由于在执行epoll_create和epoll_ctrl时,已经把用户态的信息保存到内核态了所以之后即使反复地调用epoll_wait,也不会重复地拷贝参数,扫描文件描述符,反复地把当前进程放入/放出等待队列。这样就避免了以上的三个缺点。

 

selectpollepoll_wait参数及实现对比


1.   int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);    

      select的第一个参数nfdsfdset集合中最大描述符值加1fdset是一个位数组,其大小限制为__FD_SETSIZE1024),位数组的每一位代表其对应的描述符是否需要被检查。

 

select的第二三四个参数表示需要关注读、写、错误事件的文件描述符位数组,这些参数既是输入参数也是输出参数,可能会被内核修改用于标示哪些描述符上发生了关注的事件。所以每次调用select前都需要重新初始化fdset

 

timeout参数为超时时间,该结构会被内核修改,其值为超时剩余的时间。

 

select对应于内核中的sys_select调用,sys_select首先将第二三四个参数指向的fd_set拷贝到内核,然后对每个被SET的描述符调用进行poll,并记录在临时结果中(fdset),如果有事件发生,select会将临时结果写到用户空间并返回;当轮询一遍后没有任何事件发生时,如果指定了超时时间,则select会睡眠到超时,睡眠结束后再进行一次轮询,并将临时结果写到用户空间,然后返回。

 

select返回后,需要逐一检查关注的描述符是否被SET(事件是否发生)。

 

2.  pollselect不同,通过一个pollfd数组向内核传递需要关注的事件,故没有描述符个数的限制,pollfd中的events字段和revents分别用于标示关注的事件和发生的事件,故pollfd数组只需要被初始化一次。

 

poll的实现机制与select类似,其对应内核中的sys_poll,只不过poll向内核传递pollfd数组,然后对pollfd中的每个描述符进行poll,相比处理fdset来说,poll效率更高。

 

poll返回后,需要对pollfd中的每个元素检查其revents值,来得指事件是否发生。

 

3.  epoll通过epoll_create创建一个用于epoll轮询的描述符,通过epoll_ctl添加/修改/删除事件,通过epoll_wait检查事件,epoll_wait的第二个参数用于存放结果。

 

epollselectpoll不同,首先,其不用每次调用都向内核拷贝事件描述信息,在第一次调用后,事件信息就会与对应的epoll描述符关联起来。另外epoll不是通过轮询,而是通过在等待的描述符上注册回调函数,当事件发生时,回调函数负责把发生的事件存储在就绪事件链表中,最后写到用户空间。

 

epoll返回后,该参数指向的缓冲区中即为发生的事件,对缓冲区中每个元素进行处理即可,而不需要像pollselect那样进行轮询检查。

 

selectpollepoll_wait性能对比

selectpoll的内部实现机制相似,性能差别主要在于向内核传递参数以及对fdset的位操作上,另外,select存在描述符数的硬限制,不能处理很大的描述符集合。这里主要考察pollepoll在不同大小描述符集合的情况下性能的差异。

 

测试程序会统计在不同的文件描述符集合的情况下,1spollepoll调用的次数。统计结果如下,从结果可以看出,对poll而言,每秒钟内的系统调用数目虽集合增大而很快降低,而epoll基本保持不变,具有很好的扩展性。

 

描述符集合大小

poll

epoll

1

331598

258604

10

330648

297033

100

91199

288784

1000

27411

296357

5000

5943

288671

10000

2893

292397

25000

1041

285905

50000

536

293033

100000

224

285825


epoll和Epoll内核实现机制:http://www.cppblog.com/feixuwu/archive/2010/07/10/119995.html

原文链接:http://www.cnblogs.com/xuxm2007/archive/2011/08/15/2139809.html

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
selectpollepoll都是用于多路复用IO的机制,用于同时监听多个文件描述符的就绪状态。它们的原理和区别如下: 1. selectpoll的原理是通过遍历所有需要监听的文件描述符来检查是否就绪。select使用fd标注位来存放需要监听的文件描述符,而poll使用链表来存储文件描述符。因此,select会受到最大连接数的限制,而poll不会。而epoll采用回调机制,只需要处理已经就绪的文件描述符。 2. selectpoll在返回时不会明确指出哪些文件描述符已经就绪,需要在程序中遍历所有监听的文件描述符来找到就绪的文件描述符。而epoll会直接返回已经就绪的文件描述符,省去了遍历的步骤。 3. selectpoll采用轮询的方式来检查文件描述符是否就绪,效率会随着文件描述符数量的增加而线性降低。而epoll采用回调机制,在活跃的socket很多时效率不会受到太大影响。 4. epoll支持边缘触发和水平触发两种模式,边缘触发模式效率更高。而selectpoll只支持水平触发模式。 5. selectpoll需要将相关的文件描述符的数据结构拷贝进内核,再拷贝出来。而epoll的文件描述符数据结构存储在内核态中,利用mmap文件映射内存加速与内核空间的消息传递,减少了复制的开销。 总结来说,selectpoll使用轮询方式来检查文件描述符是否就绪,效率较低,而epoll采用回调机制,效率更高。epoll支持边缘触发模式和水平触发模式,而selectpoll只支持水平触发模式。epoll的文件描述符数据结构存储在内核态中,减少了复制开销。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [epollpollselect的原理和区别](https://blog.csdn.net/wwwvipp/article/details/119888373)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [[14本经典Android开发教程]-8-Linux内核阅读心得体会](https://download.csdn.net/download/cleopard/8391591)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值