poll和select有什么区别?


Answers:


90

我认为这可以回答您的问题:

从Richard Stevens(rstevens@noao.edu):

基本区别在于select()的fd_set是位掩码,因此具有某些固定大小。编译内核时,内核可能不会限制此大小,从而允许应用程序将FD_SETSIZE定义为所需的大小(正如今天系统头中的注释所暗示的),但它需要做更多的工作。4.4BSD的内核和Solaris库功能都有此限制。但是我看到现在已经对BSD / OS 2.1进行了编码以避免这种限制,因此它是可行的,仅需编程即可。:-)有人应该对此提交一份Solaris Bug报告,并查看它是否得到修复。

但是,使用poll()时,用户必须分配一个pollfd结构数组,并传递该数组中的条目数,因此没有基本限制。正如Casper所指出的那样,具有poll()的系统少于select的系统,因此后者更具可移植性。同样,使用原始实现(SVR3),您无法将描述符设置为-1来告诉内核忽略pollfd结构中的条目,这使得很难从数组中删除条目;SVR4解决了这个问题。就我个人而言,我总是使用select()而很少使用poll(),因为我也将代码移植到了BSD环境中。对于这些环境,有人可以编写使用select()的poll()的实现,但是我从未见过这样的实现。POSIX 1003.1g正在将select()和poll()标准化。

2017年10月更新:

以上引用的电子邮件至少与2001年一样古老;poll()现在(2017)在所有现代操作系统(包括BSD)中都支持该命令。实际上,有些人认为select() 应该弃用。除了观点,围绕可移植性的问题poll()不再是现代系统的关注点。此外,epoll()自从开发出(您可以阅读手册页)以来,它的受欢迎程度持续上升。

对于现代开发,您可能不想使用select(),尽管没有任何明显的错误。 poll(),并且它是更现代的演变epoll(),提供了相同的功能(以及更多),select()而没有受到其中的限制。


15
史蒂文斯的答案是什么时候写的?关于poll()在BSD上不可用的评论是否仍然适用?MacOS X(部分基于BSD)具有poll(),而POSIX标准(POSIX 2008)需要它。
乔纳森·勒夫勒

12
Rich Stevens于1999年9月去世,因此答案必须比这个年龄大。他提到看到了BSD / OS 2.1的新变化,该变化于1996年1月发布,大概是在那时。
alanc 2010年

2
我不相信 5年前发布的答案,我偶然发现,在浏览器中保持打开状态。第二天,作者编辑并改进了答案。SO使用AJAX / websocket通知我页面更新。这就是为什么SO很棒的原因
Steven Lu

9
@StevenLu是的,但是很遗憾,没有关于AJAX / websocket是使用select还是poll:(
Christopher Schultz

>对于这些环境,有人可以编写使用select()的poll()实现,但我从未见过。Java这样做;-)
Sergey Mashkov

229

select()调用使您创建了三个位掩码,以标记要监视的套接字和文件描述符,以查看它们的读取,写入和错误,然后操作系统标记哪些套接字和文件描述符实际上具有某种活动。poll()您是否创建了描述符ID列表,并且操作系统用发生的事件类型标记了每个描述符。

select()方法相当笨拙且效率低下。

  1. 通常,一个进程可以使用一千多个潜在文件描述符。如果长时间运行的进程仅打开了几个描述符,但是至少其中一个分配了高编号,则传递给的位掩码select()必须足够大以容纳最高的描述符-因此数百个位的整个范围将不必担心操作系统必须在每次select()调用时循环,以发现它们未设置。

  2. 一旦select()返回,调用者必须遍历所有三个位掩码以确定发生了什么事件。在许多典型应用中,在任何给定时刻只有一个或两个文件描述符将获得新的通信量,但是必须一直读取所有三个位掩码以发现那些描述符。

  3. 由于操作系统会通过重写位掩码来向您发出有关活动的信号,因此它们被破坏了,并且不再用您要收听的文件描述符列表进行标记。您要么必须从保存在内存中的其他列表中重建整个位掩码,要么必须memcpy()在每个select()调用之后在每个损坏的位掩码之上保留每个位掩码和数据块的副本。

因此该poll()方法效果更好,因为您可以继续重复使用相同的数据结构。

实际上,poll()它启发了现代Linux内核中的另一种机制:epoll()对该机制进行了进一步改进,以实现可扩展性的又一次飞跃,因为当今的服务器通常希望一次处理成千上万的连接。这是对工作的良好介绍:

http://scotdoyle.com/python-epoll-howto.html

尽管此链接有一些不错的图表,它们显示了epoll()()的好处(您会注意到,select()到目前为止,它被认为是效率低下且过时的,因此甚至无法在这些图表上显示一条直线!):

http://lse.sourceforge.net/epoll/index.html


更新:这是另一个堆栈溢出问题,其答案甚至提供了有关差异的更多详细信息:

Twisted中Select / Poll与Epoll反应器的警告


1
和+1链接到在python中使用epoll的示例-看起来那里有一些有趣的示例,我将不得不尝试一下...
艾伦·乔治

+1用于解释答案;-1代表提及epoll,但未提及kqueue
好人

这个答案听起来像是epoll总是可取的
user3467349 2015年

0

两者都很慢,并且几乎相同,但是大小和功能有所不同!

编写迭代器时,您select每次都需要复制该集合!在poll修复了此类问题时就有了漂亮的代码。另一个区别是,poll默认情况下可以处理1024个以上的文件描述符(FD)。poll可以处理不同的事件以使程序更具可读性,而不用拥有很多变量来处理此类工作。在操作pollselect是线性的并且因为具有许多检查的慢。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.