在无限循环中,我正在使用 select 监听 100 多个文件描述符。如果 fd 有一些数据包可供读取,我会通知分配给此文件描述符的数据包处理器线程,并且不会为下一轮设置此文件描述符的位,直到我收到来自数据处理器线程的通知,表示已完成。我想知道如果我不计算最大值,我的代码会有多低效。每次我从集合中清除/设置文件描述符时,都会选择 fd 。我期望文件描述符几乎是连续的,每个 fd 的数据到达率为每秒几千字节。
您确实应该使用
poll
而不是 select
。两者都是标准的,但 poll
更易于使用,不会限制您可以检查的文件描述符的数量(而 select
限制您使用编译时常量 FD_SETSIZE
),并且效率更高。如果您确实使用 select
,则始终可以将 FD_SETSIZE
作为第一个参数,但这当然会带来最坏情况的性能,因为内核必须扫描整个 fd_set
;传递实际的 max+1 可以缩短搜索时间,但仍然不如传递给 poll
的数组高效。
不管怎样,现在使用非标准 Linux
epoll
或任何 BSD 同等产品似乎很时尚。如果您有大量(数万个)长期(至少几次往返)连接,这些接口可能具有一些优势,但否则性能不会明显更好(并且,在低端,可能更糟),而且这些接口当然是不可移植的,在我看来,比普通的、便携式的poll
更难正确使用。
原则上,为
select
提供一个良好的 max fd 非常重要(但进程中只有几百个文件描述符,这并不重要)。
但是
select
正在变得过时(正是因为最大 fd,因此内核将花费 O(m) 时间,其中 m 是 max.fd;因此,如果在最大 m很大的一小组文件描述符)。使用 poll(2) 代替(当给定一组 n 文件描述符时,需要 O(n) 时间,与最大文件描述符 m 无关)。 当前的 Linux 系统和进程可能有数十万个文件描述符。了解C10K 问题事件循环
,例如使用像 libevent 或 libev 这样的库(可能在内部使用 ̀select
,并且可能使用更多操作系统特定的东西,比如
poll
等......将它们抽象到一个方便的接口中)