98

我阅读和体验过的所有内容(基于 Tornado 的应用程序)都让我相信 ePoll 是基于 Select 和 Poll 的网络的自然替代品,尤其是 Twisted。这让我很偏执,因为一种更好的技术或方法不付出代价是非常罕见的。

阅读 epoll 和替代方案之间的几十个比较表明,epoll 显然是速度和可扩展性的冠军,特别是它以线性方式扩展,这太棒了。也就是说,处理器和内存利用率如何,epoll 仍然是冠军吗?

4

2 回答 2

196

对于非常少量的套接字(当然,取决于您的硬件,但我们谈论的是大约 10 个或更少的套接字),select 可以在内存使用和运行速度方面击败 epoll。当然,对于如此少量的套接字,两种机制都非常快,以至于在绝大多数情况下您并不真正关心这种差异。

不过,有一个澄清。select 和 epoll 都是线性缩放的。但是,一个很大的区别是面向用户空间的 API 具有基于不同事物的复杂性。调用的成本select大致与您传递给它的编号最高的文件描述符的值有关。如果您在单个 fd 上选择 100,那么这大约是在单个 fd 上选择 50 的两倍。在最高值以下添加更多 fd 并不是完全免费的,因此在实践中它比这更复杂一些,但这对于大多数实现来说是一个很好的初步近似。

epoll 的成本更接近于实际上有事件的文件描述符的数量。如果您正在监视 200 个文件描述符,但其中只有 100 个有事件,那么您(非常粗略地)只需为这 100 个活动文件描述符付费。这就是 epoll 倾向于提供其优于 select 的主要优势之一的地方。如果您有一千个大部分空闲的客户,那么当您使用 select 时,您仍然需要为全部一千个客户付费。但是,使用 epoll,就好像您只有几个 - 您只需为在任何给定时间处于活动状态的那些付费。

这一切意味着 epoll 将导致大多数工作负载的 CPU 使用率降低。就内存使用而言,这有点折腾。 select确实设法以高度紧凑的方式表示所有必要的信息(每个文件描述符一位)。FD_SETSIZE(通常为 1024)限制您可以使用多少个文​​件描述符,select这意味着您可以使用的三个 fd 集合中的每一个都不会花费超过 128 个字节select(读,写,异常)。与最大 384 字节相比,epoll 有点像猪。每个文件描述符都由一个多字节结构表示。但是,绝对而言,它仍然不会使用太多内存。您可以在几十 KB 中表示大量文件描述符(我认为每 1000 个文件描述符大约 20k)。select如果您只想监视一个文件描述符但它的值恰好是 1024,那么您也可以考虑这样一个事实,即您必须花费所有 384 个字节,而使用 epoll 您只花费 20 个字节。尽管如此,所有这些数字都非常小,因此并没有太大区别。

epoll 还有其他好处,也许您已经知道,它不限于 FD_SETSIZE 文件描述符。您可以使用它来监控尽可能多的文件描述符。如果你只有一个文件描述符,但它的值大于 FD_SETSIZE,那么 epoll 也可以使用它,但select不能。

随机地,我最近还发现了与orepoll相比的一个小缺点。虽然这三个 API 都不支持普通文件(即,文件系统上的文件),但由于报告此类描述符始终可读且始终可写,因此缺乏支持。这使得它们不适合任何有意义的非阻塞文件系统 I/O,使用或碰巧遇到来自文件系统的文件描述符的程序将至少继续运行(或者如果它失败,它不会是因为of or ),尽管它的性能可能不是最好的。selectpollselectpollselectpollselectpoll

另一方面,当被要求监视这样的文件描述符时,epoll将很快失败并出现错误(显然)。EPERM严格来说,这几乎是不正确的。它只是以明确的方式表明它缺乏支持。通常我会为明确的失败条件鼓掌,但是这个没有记录(据我所知)并导致一个完全损坏的应用程序,而不是一个仅以潜在性能下降的方式运行的应用程序。

在实践中,我看到这个出现的唯一地方是与 stdio 交互时。用户可能会将标准输入或标准输出从/重定向到普通文件。而以前的标准输入和标准输出本来是一个管道——epoll 支持得很好——然后它变成了一个普通文件,epoll 大声失败,破坏了应用程序。

于 2010-01-09T15:11:20.610 回答
4

在我公司的测试中,出现了 epoll() 的一个问题,因此与 select 相比只有一个成本。

当尝试从网络中读取超时时,创建一个 epoll_fd(而不是 FD_SET),并将 fd 添加到 epoll_fd,比创建一个 FD_SET(这是一个简单的 malloc)要昂贵得多。

根据前面的回答,随着过程中FD的数量变大,select()的成本会越来越高,但是在我们的测试中,即使fd值在10,000个,select仍然是赢家。在这些情况下,线程只有一个 fd 正在等待,并且只是试图克服网络读取和网络写入在使用阻塞线程模型时不会超时的事实。当然,与非阻塞反应器系统相比,阻塞线程模型的性能较低,但在某些情况下,为了与特定的遗留代码库集成,它是必需的。

这种用例在高性能应用程序中很少见,因为反应器模型不需要每次都创建一个新的 epoll_fd。对于 epoll_fd 长期存在的模型——这显然是任何高性能服务器设计的首选——epoll 在各方面都是明显的赢家。

于 2014-04-30T07:33:05.820 回答