【发布时间】:2010-11-01 13:00:01
【问题描述】:
【问题讨论】:
【问题讨论】:
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 问题,其答案提供了有关差异的更多详细信息:
【讨论】:
struct pollfd 数组更有效,因为您也需要间隙,否则非间隙的维护将比 fd_set 操作昂贵得多)。
我认为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。
上面提到的电子邮件至少与 2001 年一样古老; poll() 命令现在 (2017) 支持所有现代操作系统 - 包括 BSD。其实也有人相信select()should be deprecated。除了意见之外,围绕poll() 的可移植性问题不再是现代系统所关心的问题。此外,epoll() 已经被开发出来(你可以read the man page),并且越来越受欢迎。
对于现代开发,您可能不想使用select(),尽管它并没有明显的错误。 poll(),它是更现代的进化 epoll(),提供与 select() 相同的功能(甚至更多),而不受其中的限制。
【讨论】:
select 还是poll 的消息:(
它们都慢并且大部分相同,但大小和某些功能不同!
编写迭代器时,每次都需要复制select的集合!而poll 已经解决了这类问题以拥有漂亮的代码。另一个区别是poll 默认可以处理超过 1024 个文件描述符 (FD)。 poll 可以处理不同的事件以使程序更具可读性,而不是有很多变量来处理这种工作。 poll 和 select 中的操作是线性且缓慢的,因为有很多检查。
【讨论】: