民意调查和select有什么区别?
我指的是POSIX标准select和轮询系统C API调用。
我认为这回答你的问题:
来自Richard Stevens(rstevens@noao.edu):
基本的区别是select()的fd_set是一个位掩码,因此有一些固定的大小。 当内核被编译时,内核可能不会限制这个大小,允许应用程序根据需要定义FD_SETSIZE(正如系统头文件中的注释所暗示的那样),但是需要更多的工作。 4.4BSD的内核和Solaris库函数都有这个限制。 但是我发现BSD / OS 2.1现在已经被编码,以避免这个限制,所以它是可行的,只是一个小的编程问题。 :-)有人应该就此提交一份Solaris错误报告,看看它是否得到解决。
然而,使用poll(),用户必须分配一个pollfd结构数组,并传递该数组中的条目数,所以没有根本的限制。 正如Casper所指出的,更less的系统具有poll()而不是select,所以后者更具可移植性。 另外,对于原始实现(SVR3),您不能将描述符设置为-1,以告知内核忽略pollfd结构中的条目,这使得难以从数组中移除条目; SVR4解决这个问题。 就个人而言,我总是使用select()和很lesspoll(),因为我也将我的代码移植到BSD环境中。 有人可以写一个使用select()的poll()的实现,对于这些环境,但我从来没有见过。 POSIX 1003.1g对select()和poll()都进行了标准化。
2017年10月更新:
上面引用的电子邮件至less和2001年一样早; poll()
命令现在(2017)支持所有现代操作系统 – 包括BSD。 事实上,有些人认为select()
应该被弃用 。 抛开一些观点,围绕poll()
可移植性问题已经不再是现代系统所关注的问题。 此外, epoll()
已经被开发出来(你可以阅读手册页 ),并继续stream行起来。
对于现代开发,你可能不想使用select()
,虽然没有明确的错误。 poll()
,它是更现代的进化epoll()
,提供与select()
相同的特性(以及更多),而不受其中的限制。
select()
调用可以创build三个位掩码,用于标记要读取,写入和错误的哪些套接字和文件描述符,然后操作系统会标记哪些套接字和文件描述符实际上具有某种活动; poll()
是否创build了描述符ID的列表,操作系统使用发生的事件types来标记每个描述符。
select()
方法相当笨重且效率低下。
-
通常有超过一千个潜在的文件描述符可用于进程。 如果一个长时间运行的进程只打开了几个描述符,但其中至less有一个已经被分配了一个高数字,那么传递给
select()
的位掩码必须足够大以容纳最高描述符 – 所以整个范围为几百的位将被取消设置,操作系统必须在每个select()
调用中循环以发现它们未被设置。 -
一旦
select()
返回,调用者必须遍历所有三个位掩码来确定发生了什么事件。 在很多典型的应用程序中,只有一个或两个文件描述符会在任何给定的时刻获得新的stream量,但是所有三个位掩码必须一直读到最后才能发现哪些描述符。 -
由于操作系统通过重写位掩码来向您显示有关活动的信息,因此它们已被毁坏,并且不再标记要收听的文件描述符列表。 您必须重新构build您保存在内存中的其他列表的整个位掩码,或者在每个
select()
调用之后,必须将每个位掩码和memcpy()
数据块的重复副本保留在被破坏位掩码的顶部。
所以poll()
方法更好,因为你可以继续使用相同的数据结构。
实际上, poll()
在现代Linux内核中启发了另外一种机制: epoll()
,它更进一步改进了机制,允许又一次的可伸缩性的飞跃,因为今天的服务器通常要同时处理数以万计的连接。 这是一个很好的介绍:
http://scotdoyle.com/python-epoll-howto.html
虽然这个链接有一些很好的图表显示了epoll()
的好处(你会注意到select()
被认为是非常低效和老式的,甚至在这些图表上也没有一行):
http://lse.sourceforge.net/epoll/index.html
更新:这是另一个堆栈溢出的问题,其答案给出了更详细的差异:
select/轮询与Twisted中的epoll反应器的注意事项