您的位置:首页 > 其它

select、poll、epoll的比较

2016-10-08 16:51 204 查看


select、poll、epoll的比较

http://my.chinaunix.net/space.php?uid=20196318&do=blog&id=366042

http://blog.endlesscode.com/2010/03/27/select-poll-epoll-intro/

 linux提供了select、poll、epoll接口来实现IO复用,三者的原型如下所示,本文从参数、实现、性能等方面对三者进行对比。

 

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);

 

selectpollepoll_wait参数及实现对比

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

 

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

 

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

 

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

 

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

 

2.  poll与select不同,通过一个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的第二个参数用于存放结果。

 

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

 

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

 

selectpollepoll_wait性能对比

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

 

测试程序会统计在不同的文件描述符集合的情况下,1s内poll与epoll调用的次数。统计结果如下,从结果可以看出,对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

 

http://www.cppblog.com/feixuwu/archive/2010/07/10/119995.html


<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>

阅读(277) | 评论(0) | 转发(0) |

0
上一篇:双核,超线程的区别

下一篇:GDB WHICH HAS NO LINE NUMBER INFO

相关热门文章
linux 常见服务端口

xmanager 2.0 for linux配置

【ROOTFS搭建】busybox的httpd...

openwrt中luci学习笔记

什么是shell

linux dhcp peizhi roc

关于Unix文件的软链接

求教这个命令什么意思,我是新...

sed -e "/grep/d" 是什么意思...

谁能够帮我解决LINUX 2.6 10...

给主人留下些什么吧!~~

评论热议
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: