poll 和 select 有啥区别?
Posted
技术标签:
【中文标题】poll 和 select 有啥区别?【英文标题】:What are the differences between poll and select?poll 和 select 有什么区别? 【发布时间】:2010-11-01 13:00:01 【问题描述】:我指的是 POSIX 标准 select 和 poll 系统 C API 调用。
【问题讨论】:
【参考方案1】:select()
调用让您创建三个位掩码来标记您要监视哪些套接字和文件描述符以进行读取、写入和错误,然后操作系统会标记哪些实际上有某种活动; poll()
让您创建了一个描述符 ID 列表,并且操作系统用发生的事件的种类标记它们中的每一个。
select()
方法相当笨重且效率低下。
通常有超过一千个潜在的文件描述符可供进程使用。如果一个长时间运行的进程只打开了几个描述符,但其中至少有一个被分配了一个高数字,那么传递给select()
的位掩码必须足够大以容纳最高的描述符——所以整个范围为数百操作系统必须循环遍历每个select()
调用才能发现它们未设置的位将被取消设置。
一旦select()
返回,调用者必须遍历所有三个位掩码以确定发生了哪些事件。在非常多的典型应用程序中,在任何给定时刻只有一两个文件描述符会获得新的流量,但是必须一直读取所有三个位掩码以发现它们是哪些描述符。
由于操作系统通过重写位掩码向您发出活动信号,因此它们已被破坏并且不再标有您要收听的文件描述符列表。您要么必须从保存在内存中的其他列表重建整个位掩码,要么必须在每次 select()
调用后保留每个位掩码的副本和 memcpy()
数据块在损坏的位掩码之上.
所以poll()
方法效果更好,因为您可以继续重复使用相同的数据结构。
事实上,poll()
启发了现代 Linux 内核中的另一种机制:epoll()
,它进一步改进了机制,以实现可扩展性的又一次飞跃,因为今天的服务器通常希望以一次。这是对这项工作的一个很好的介绍:
http://scotdoyle.com/python-epoll-howto.html
虽然这个链接有一些很好的图表显示了epoll()
的好处(你会注意到select()
在这一点上被认为是低效和过时的,它甚至在这些图表上都没有一条线!):
http://lse.sourceforge.net/epoll/index.html
更新:这是另一个 Stack Overflow 问题,其答案提供了有关差异的更多详细信息:
Caveats of select/poll vs. epoll reactors in Twisted
【讨论】:
和 +1 用于链接到在 python 中使用 epoll 的示例 - 看起来那里有一些有趣的示例,我将不得不尝试它们...... 这个答案听起来像 epoll 总是更可取 你让它看起来好像 bitscan 是瓶颈。它不是。扫描一个 1024 位数组(1024 是 Linux 上的 FD_SETSIZE)大约需要 20ns。系统调用需要数百甚至数千。可以相当有效地跳过稀疏间隙(比使用struct pollfd
数组更有效,因为您也需要间隙,否则非间隙的维护将比 fd_set 操作昂贵得多)。
根据我发现的这个基准,它们似乎与大型 fd 集一样(无效)效率:monkey.org/~provos/libevent/libevent-benchmark2.jpg,在高 fd 计数时 poll 仅获得很小的优势,可能是因为 select 修改了它的参数设置比 select 更多。【参考方案2】:
我认为this 回答了你的问题:
来自理查德·史蒂文斯 (rstevens@noao.edu):
基本区别在于select()的fd_set是一个位掩码和 因此有一些固定的大小。内核可以 内核编译时不限制这个大小,允许 应用程序将 FD_SETSIZE 定义为它想要的任何东西(作为 cmets 在系统标题中暗示今天)但它需要更多的工作。 4.4BSD的 内核和 Solaris 库函数都有这个限制。但是我 看到 BSD/OS 2.1 现在已经被编码以避免这个限制,所以它是 可行,只是编程的小事。 :-) 有人应该提交一份 Solaris 报告了这方面的错误,看看它是否会得到修复。
然而,使用 poll(),用户必须分配一个 pollfd 数组 结构,并传递此数组中的条目数,所以有 没有基本限制。正如 Casper 所指出的,拥有 poll() 的系统比 select,所以后者更便携。此外,与原 实现(SVR3)你不能将描述符设置为-1来告诉 内核忽略 pollfd 结构中的条目,这使得它 难以从数组中删除条目; SVR4 解决了这个问题。 就个人而言,我总是使用 select() 而很少使用 poll(),因为我移植了我的 代码也适用于 BSD 环境。有人可以写一个实现 对于这些环境,使用 select() 的 poll(),但我从来没有 见过一个。 select() 和 poll() 都被 POSIX 标准化 1003.1g。
2017 年 10 月更新:
上面提到的电子邮件至少与 2001 年一样古老; poll()
命令现在 (2017) 支持所有现代操作系统 - 包括 BSD。其实也有人相信select()
should be deprecated。除了意见之外,围绕poll()
的可移植性问题不再是现代系统所关心的问题。此外,epoll()
已经被开发出来(你可以read the man page),并且越来越受欢迎。
对于现代开发,您可能不想使用select()
,尽管它并没有明显的错误。 poll()
,它是更现代的进化 epoll()
,提供与 select()
相同的功能(甚至更多),而不受其中的限制。
【讨论】:
史蒂文斯的答案是什么时候写的?关于 poll() 在 BSD 上不可用的评论是否仍然适用? MacOS X(部分基于 BSD)有 poll(),POSIX 标准(POSIX 2008)需要它。 Rich Stevens 于 1999 年 9 月去世,所以答案必须比这更早。他提到在 1996 年 1 月发布的 BSD/OS 2.1 中看到了新的变化,所以可能在那个时候。 我不相信。 5年前发布的答案,我偶然发现它,让它在浏览器中打开。第二天,作者编辑并改进了答案。 SO 使用 AJAX/websocket 在页面上通知我更新。这就是为什么 SO 很棒 @StevenLu 是的,但遗憾的是没有关于 AJAX/websocket 是使用select
还是poll
的消息:(
> 有人可以为这些环境编写一个使用 select() 的 poll() 实现,但我从未见过。 Java 这样做 ;-)【参考方案3】:
它们都慢并且大部分相同,但大小和某些功能不同!
编写迭代器时,每次都需要复制select
的集合!而poll
已经解决了这类问题以拥有漂亮的代码。另一个区别是poll
默认可以处理超过 1024 个文件描述符 (FD)。 poll
可以处理不同的事件以使程序更具可读性,而不是有很多变量来处理这种工作。 poll
和 select
中的操作是线性且缓慢的,因为有很多检查。
【讨论】:
以上是关于poll 和 select 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章
socket编程的select poll和epoll这两种机制,本质区别在哪里?