代码之家  ›  专栏  ›  技术社区  ›  David

选择/轮询与EPoll反应器在扭曲状态下的注意事项

  •  89
  • David  · 技术社区  · 15 年前

    我所阅读和体验过的所有内容(基于Tornado的应用程序)都让我相信,epoll是基于选择和投票的网络的自然替代品,尤其是使用Twisted。这让我产生了妄想症,一种更好的技术或方法不需要付出代价是很罕见的。

    通过对epoll和其他产品进行几十次比较,可以看出epoll显然是速度和可扩展性方面的佼佼者,特别是它以线性方式进行扩展,这非常棒。也就是说,处理器和内存的利用率如何,epoll仍然是冠军吗?

    2 回复  |  直到 8 年前
        1
  •  184
  •   Jean-Paul Calderone    15 年前

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

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

    epoll的成本更接近于实际包含事件的文件描述符的数量。如果您监视的是200个文件描述符,但其中只有100个上面有事件,那么(非常粗略地)您只需要为这100个活动的文件描述符付费。这就是epoll比select更具优势的地方。如果你有上千个客户机大部分都是闲置的,那么当你使用Select时,你仍然要为所有的一千个客户支付费用。然而,使用epoll,就好像你只有少数人——你只为在任何给定时间活跃的人付费。

    所有这些都意味着epoll将减少大多数工作负载的CPU使用量。就内存使用而言,这有点麻烦。 选择 以高度紧凑的方式(每个文件描述符一位)表示所有必需的信息。fd_setsize(通常是1024)限制了可以与多少文件描述符一起使用 选择 也就是说,对于您可以使用的三个fd集中的每一个,您的花费永远不会超过128个字节。 选择 (读、写、异常)。与最大384字节相比,epoll有点像猪。每个文件描述符由多字节结构表示。但是,从绝对值来看,它仍然不会占用太多内存。您可以用几十个千字节来表示大量的文件描述符(我认为大约每1000个文件描述符有20K个)。你也可以考虑这样一个事实,即你必须用384个字节 选择 如果您只想监视一个文件描述符,但它的值恰好是1024,那么使用epoll时,您只需要花费20个字节。不过,所有这些数字都很小,所以没什么区别。

    还有epoll的另一个好处,也许您已经知道了,它不局限于fd setize文件描述符。您可以使用它来监视尽可能多的文件描述符。如果您只有一个文件描述符,但其值大于fd_setsize,epoll也可以使用它,但是 选择 没有。

    随机地,我最近还发现了 epoll 相比之下 选择 poll . 虽然这三个API都不支持普通文件(即文件系统上的文件), 选择 民意测验 呈现出这种缺乏支持的情况,比如将描述符报告为始终可读和始终可写。这使得它们不适合任何有意义的非阻塞文件系统I/O,一个使用 选择 民意测验 碰巧遇到来自文件系统的文件描述符,它至少会继续运行(或者如果失败,它不会因为 选择 民意测验 ,尽管它可能没有最好的性能。

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

    在实践中,我看到的唯一一个地方是与stdio交互时。用户可以将stdin或stdout从/重定向到普通文件。以前的stdin和stdout应该是一个管道,由epoll支持,但很好,然后它变成一个普通文件,epoll会很大声地失败,从而破坏应用程序。

        2
  •  4
  •   Brian Bulkowski    11 年前

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

    当试图在超时情况下从网络中读取数据时,创建epoll_fd(而不是fd_集),并将fd添加到epoll_fd,比创建fd_集(这是一个简单的malloc)要昂贵得多。

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

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

    推荐文章