select/poll/epoll 对比

前两篇文章介绍了select,poll,epoll的基本用法,如今咱们来看看它们的区别和适用场景。html

首先仍是来看常见的select和poll。对于网络编程来讲,通常认为poll比select要高级一些,这主要源于如下几个缘由:编程

  1. poll() 不要求开发者计算最大文件描述符加一的大小。
  2. poll() 在应付大数目的文件描述符的时候速度更快,由于对于select()来讲内核须要检查大量描述符对应的fd_set 中的每个比特位,比较费时。
  3. select 能够监控的文件描述符数目是固定的,相对来讲也较少(1024或2048),若是须要监控数值比较大的文件描述符,就算所监控的描述符不多,若是分布的很稀疏也会效率很低,对于poll() 函数来讲,就能够建立特定大小的数组来保存监控的描述符,而不受文件描述符值大小的影响,并且poll()能够监控的文件数目远大于select。
  4. 对于select来讲,所监控的fd_set在select返回以后会发生变化,因此在下一次进入select()以前都须要从新初始化须要监控的fd_set,poll() 函数将监控的输入和输出事件分开,容许被监控的文件数组被复用而不须要从新初始化。
  5. select() 函数的超时参数在返回时也是未定义的,考虑到可移植性,每次在超时以后在下一次进入到select以前都须要从新设置超时参数。

  固然也不是说select就没有优势:数组

  1. select()的可移植性更好,在某些Unix系统上不支持poll()
  2. select() 对于超时值提供了更好的精度:微秒,而poll是毫秒。

epoll的优势:服务器

1.支持一个进程打开大数目的socket描述符(FD)网络

  select 最不能忍受的是一个进程所打开的FD是有必定限制的,由FD_SETSIZE设置,默认值是1024/2048。对于那些须要支持的上万链接数目的IM服务器来讲显然太少了。这时候你一是能够选择修改这个宏而后从新编译内核。不过 epoll则没有这个限制,它所支持的FD上限是最大能够打开文件的数目,这个数字通常远大于2048,举个例子,在1GB内存的机器上大约是10万左右,具体数目能够cat /proc/sys/fs/file-max察看,通常来讲这个数目和系统内存关系很大。socket

2.IO效率不随FD数目增长而线性降低函数

  传统的select/poll另外一个致命弱点就是当你拥有一个很大的socket集合,不过因为网络延时,任一时间只有部分的socket是"活跃"的,可是select/poll每次调用都会线性扫描所有的集合,致使效率呈现线性降低。可是epoll不存在这个问题,它只会对"活跃"的socket进行操做---这是由于在内核实现中epoll是根据每一个fd上面的callback函数实现的。那么,只有"活跃"的socket才会主动的去调用 callback函数,其余idle状态socket则不会,在这点上,epoll实现了一个"伪"AIO,由于这时候推进力在Linux内核。htm

3.使用mmap加速内核与用户空间的消息传递。blog

  这点实际上涉及到epoll的具体实现了。不管是select,poll仍是epoll都须要内核把FD消息通知给用户空间,如何避免没必要要的内存拷贝就很重要,在这点上,epoll是经过内核与用户空间mmap同一块内存实现的。 队列

  对于poll来讲须要将用户传入的 pollfd 数组拷贝到内核空间,由于拷贝操做和数组长度相关,时间上这是一个O(n)操做,当事件发生,poll返回将得到的数据传送到用户空间并执行释放内存和剥离等待队列等善后工做,向用户空间拷贝数据与剥离等待队列等操做的的时间复杂度一样是O(n)。

 

  这两天看到一个云风他们那里的bug就是由于使用的开源库中做者使用了非阻塞connect使用select() 来等待超时,可是并未检查FD_SETSIZE,当文件描述符数目大于这个数目以后就会出现内存越界错误,形成coredump。

相关文章
相关标签/搜索