Answers:
在“UNIX环境高级编程”,理查德·史蒂文斯说,这是一个性能优化:
通过指定我们感兴趣的最高描述符,内核可以避免遍历三个描述符集中的一百个未使用的位,寻找打开的位。
(第1版,第399页)
如果您要进行任何类型的UNIX系统编程,强烈建议您阅读APUE。
更新
一个fd_set
通常能够追踪多达1024个文件描述符。
跟踪fds
设置为0
和设置为的最有效方法是位集1
,因此每个fd_set
位都包含1024位。
在32位系统上,long int(或“ word”)为32位,因此意味着每个int fd_set
为
1024/32 = 32个字。
如果nfds
在某些应用程序中会用到较小的值(例如8或16),则只需要查看第一个单词的内部,显然应该比查看全部32个单词的速度快。
(请参见FD_SETSIZE
和__NFDBITS
从中/usr/include/sys/select.h
获取平台上的值。)
更新2
至于为什么功能签名不是
int select(fd_set *readfds, int nreadfds,
fd_set *writefds, int nwritefds,
fd_set *exceptfds, int nexceptfds,
struct timeval *timeout);
我的猜测是,因为代码试图将所有参数保留在寄存器中,所以CPU可以更快地对其进行处理,并且如果必须跟踪额外的2个变量,则CPU可能没有足够的寄存器。
因此,换句话说,select
是公开一个实现细节,以便可以更快。
我不确定,因为我不是select()的设计师之一,但我会说这是性能优化。调用函数知道它在读取,写入和FD之外放入了多少个文件描述符,那么内核为什么还要重新找出它呢?
请记住,在80年代初引入select()时,他们没有多千兆赫,多处理器可以使用。25 MHz的VAX速度很快。另外,如果可能,您希望select()快速运行:如果某些I / O正在等待进程,为什么要让进程等待?
nreadfds
,nwritefds
而nexceptfds
不是一个nfds
。
nfds
可以将其放入寄存器中以加快访问速度。如果必须跟踪三个数字以及所有其他参数,则可能CPU将没有足够的寄存器。当然,内核可以nfds
根据您的假设3个变量创建自己的内核。因此,我的猜测是它公开了实现细节以提高效率。
nfds
论点不会带来什么好处。在大多数情况下,该流程相对于而言打开的流程很少FD_SETSIZE
。典型情况下,可能有(4,4,2)个,即1024个;进行内核检查(4,4,4)是(1024,1024,1024)的重大胜利,但优化到(4,4,2)几乎是无用的。
nfds
,或者懒得打电话select(FD_SETSIZE, ...)
,这会比较慢。)