select,poll,epoll的区别 各自支持的最大fd数上限以及原因

各自支持的最大fd数上限以及原因

select支持的fd数是固定的,默认一般为1024,用一个常数FD_SETSIZE定义,如果要monitor更多的fd,需要修改这个常数,并且重新编译(?),一般如果要monitor超过1024的fd,推荐使用poll/epoll

poll和epoll,因为他们monitor的fd list是通过数组或者说链表来保存,所以没有数量限制

区别

select

select是三者中最早被使用的多路复用机制,因此可移植性最好

通过给定三个fd set(bit mask),分别对应关注的是否可读,可写,是否出现异常三种类别,在调用select的时候,这三个集合被传给内核,内核逐一检测这些fd是否ready,然后把三个集合中ready的fd对应的bit置为1,返回

然后用户再逐一检测set中的fd是否处于ready,如果是,就对对应的fd执行相应的操作

注意到,在上面的描述中,用户始终需要扫描整个集合,也就是说扫描的个数和io事件的个数无关,而是始终是FD_SETSIZE,为了提高效率,我们可以使用一个maxfd,这样可以只检测maxfd以下的,从而扫描的个数正比于监听的fd个数,而不是始终是固定的FD_SETSIZE

缺点:

1.每次调用select都需要把三个集合传给内核,然后内核又把修改过的三个集合传回来,耗费时间

2.扫描时耗时与monitor的fd个数成正比,所以如果监听的个数很多,就会很慢

3.监听个数有上限

poll

基本和select相同,优点是监听的fd没有数量限制(因为poll不是用bit mask保存关注的fd,而是用pollfd 结构体数组

epoll

首先他和poll一样,监听的fd数没有限制(或者说只受硬件配置限制

为什么epoll的性能更好:

1.每次有io event让fd编程ready,内核都把该ready fd加入到epoll ready list,执行wait的时候直接从ready list里取而select每次调用都要扫描所有的fd

2.每次调用select/poll,都把三个set传给内核,然后内核把ready的用三个set传回来而epoll,使用epoll_ctl在内核里创建一个数据结构,之后epoll_wait时不需要传什么数据

返回的时候,也只返回ready的(事实上因为返回时我们也必须检查所有的位,判断是否ready,而epoll只返回ready的,所以还是有区别的

3.每次调用select之前,都必须初始化三个集合,还有返回之后必须检查所有的位(不过貌似这些是小头

我们可以说select/poll的耗时和N(fd数)呈线性关系,epoll的耗时和发生的io事件呈线性关系

所以epoll十分实用下面这种情况:monitor大量的fd,但是其中大部分是空闲的(因此io事件相对较少

此外epoll还提供edge trigger和level trigger两种形式的通知,而select/poll 都只支持level trigger

这两种的区别在于:

level trigger:只要fd处于ready(可读可写),就会报告给用户

edge trigger:仅当上一次调用epoll_wait之后有新的io事件,才报告给用户(如果是之前没有使用epoll_wait,那么就看创建fd之后有没有新的io事件)

举例说明edge trigger和level trigger的区别

假设现在一个fd处于ready,可读,我们执行一次epoll wait,此时一定是ready,不管采用level trigger还是edge trigger

再执行一次,如果是level trigger,那么仍然报告ready

但如果是edge trigger,那么就不会报告ready,因为从上次调用epoll wait以来,没有发生io事件

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页