如何最有效地处理大量的文件描述符?

似乎有几个选项可用于处理大量套接字连接的程序(如Web服务,p2p系统等)。

  1. 产生一个单独的线程来处理每个套接字的I / O。
  2. 使用select系统调用将I / O复用到单个线程中。
  3. 使用轮询系统调用来复用I / O(replaceselect)。
  4. 使用epoll系统调用来避免不得不在用户/系统边界重复发送套接字fd。
  5. 产生许多I / O线程,每个线程使用轮询API复用相对较less的一组连接总数。
  6. 除了使用epoll API为每个独立的I / O线程创build一个单独的epoll对象之外,按照#5。

在多核CPU上,我认为#5或者#6会有最好的性能,但是我没有任何硬盘数据支持。 search网页翻开了这个页面,描述了作者testing方法#2,#3和#4的经验。 不幸的是,这个网页似乎是7岁左右,没有明显的最新更新被发现。

所以我的问题是,这些方法中的哪些方法被人们发现是最有效率的和/或是否有另一种方法比上面列出的方法更好? 将参考现实生活的图表,白皮书和/或networking可用的写作,将不胜感激。

说到运行大型IRC服务器的经验,我们使用select()和poll()(因为epoll()/ kqueue()不可用)。 在约700个并发客户端,服务器将使用100%的CPU(irc服务器不是多线程的)。 然而,有趣的是,服务器仍然表现良好。 在大约4000个客户端,服务器将开始滞后。

原因是在大约700个客户端,当我们回到select()时,会有一个客户端可用于处理。 for()循环扫描找出它是哪个客户端将吃掉大部分的CPU。 随着我们得到更多的客户,我们会开始越来越多的客户需要处理每个电话select(),所以我们会变得更有效率。

搬到epoll()/ kqueue(),类似的spec'd机器将平凡地处理10,000个客户,有一些(肯定是更强大的机器,但仍然认为是微小的机器,今天的标准),已经拥有30,000客户没有打破汗。

我在SIGIO上看到的实验似乎表明,它适用于延迟极其重要的应用程序,在这些应用程序中只有少数活动客户端执行的工作量很小。

我建议几乎在任何情况下都使用select()/ poll()方法来使用epoll()/ kqueue()。 我还没有尝试在线程之间拆分客户端。 说实话,我从来没有发现需要在前端客户端处理上做更多的牺牲工作来证明线程的实验。

我花了2年的时间来研究这个特定的问题(对于G-WAN网络服务器来说,这个服务器有很多基准和图表都暴露了这些)。

在Linux下效果最好的模型是带有一个事件队列的epoll(对于繁重的处理,还有几个工作线程)。

如果你有很少的处理(低处理延迟),那么使用一个线程将使用多个线程更快。

原因是epoll在多核CPU上不能扩展(在同一个用户模式下使用几个并发的epoll队列连接I / O只会使服务器变慢)。

我没有认真看待内核中的epoll代码(我只专注于用户模式),但我的猜测是内核中的epoll实现被锁定损坏。

这就是为什么使用多个线程快速撞墙。

不言而喻,如果Linux想保持自己作为性能最好的内核之一的地位,这种糟糕的状态不应该持续下去。

根据我的经验,你会有#6最好的表现。

我也建议你看看libevent处理抽象的一些细节。 至少,你可以看到他们的一些基准 基准结果

另外,你有多少插座你在说什么? 你的方法可能无关紧要,直到你开始至少有几百个套接字。

我广泛使用epoll(),它表现良好。 我通常有数以千计的插座活跃,并测试多达131,072个插座。 和epoll()总是可以处理它。

我使用多个线程,每个线程轮询套接字的一个子集。 这使代码复杂化,但充分利用了多核CPU。