13

我试图弄清楚什么是性能更高的、边缘触发的或电平触发的 epoll。

主要是我将“性能”视为:

  1. 能够处理多个连接而不会降级。

  2. 能够保持每个入站消息的最高速度。

我其实更关心#2,但#1 也很重要。

我一直在使用单线程使用者(使用 接受/读取多个套接字连接epoll_wait)和多个生产者运行测试。

到目前为止,我没有看到任何区别,甚至多达 1000 个文件描述符。

我一直在这个想法(错觉?)下工作,边缘触发应该更有性能,因为会收到更少的中断。这是一个正确的假设吗?

我的测试的一个问题可能是掩盖了性能差异,即我不会在收到消息后将消息发送到线程,因此更少的中断并不重要。我一直不愿意做这个测试,因为我一直在使用__asm__ rdtsc我的“时间戳”,所以我不想协调我的原始时间戳来自哪个核心。

更让我怀疑的是,级别触发的 epoll 在我见过的一些基准测试中表现更好。

哪个更好?在什么情况下?没有区别吗?任何见解将不胜感激。

我的套接字是非阻塞的。

4

3 回答 3

14

我不希望看到触发边缘和水平之间的巨大性能差异。

对于边缘触发,您总是必须排空输入缓冲区,因此您有一个无用的(仅返回 EWOULDBLOCK)recv 系统调用。但是对于触发级别,您可能会使用更多的 epoll_wait 系统调用。正如手册页所指出的,在关卡触发模式下避免饥饿可能会稍微容易一些。

真正的区别在于,当您想使用多个线程时,您必须使用边缘触发模式(尽管您仍然必须小心正确地进行同步)。

于 2012-12-13T09:24:21.097 回答
4

仅当您使用长期会话并且由于缓冲区已满/空(通常使用代理)而被迫不断停止/启动时,差异才可见。当你这样做的时候,你最经常需要一个事件缓存,而当你的事件缓存正在处理事件时,你可以使用 ET 并避免所有的 epoll_ctl(DEL)+epoll_ctl(ADD) 跳舞。对于短期会话,节省的空间不太明显,因为对于 ET,您至少需要一个 epoll_ctl(ADD) 调用来启用 FD 上的轮询,并且如果您不希望在会话的生命周期内拥有更多这样的调用(例如:交易所在大多数情况下都小于缓冲区),那么您不应该期望有任何区别。您的大部分节省通常来自仅使用事件缓存,因为您通常可以执行大量操作(例如:写入)而无需轮询,这要归功于内核缓冲区。

于 2014-11-18T18:10:58.977 回答
1

当用作边缘触发接口时,出于性能原因,可以通过指定 (EPOLLIN|EPOLLOUT) 在 epoll 接口 (EPOLL_CTL_ADD) 内添加一次文件描述符。这允许您避免在 EPOLLIN 和 EPOLLOUT 之间不断切换,使用 EPOLL_CTL_MOD 调用 epoll_ctl(2)。

Q9 使用 EPOLLET 标志(边缘触发行为)时,我是否需要连续读取/写入文件描述符直到 EAGAIN?

   A9  Receiving  an  event  from epoll_wait(2) should suggest to you that
       such file descriptor is ready for the requested I/O operation.  You
       must  consider  it  ready  until  the next (nonblocking) read/write
       yields EAGAIN.  When and how you will use the  file  descriptor  is
       entirely up to you.

       For packet/token-oriented files (e.g., datagram socket, terminal in
       canonical mode), the only way to detect the end of  the  read/write
       I/O space is to continue to read/write until EAGAIN.

       For  stream-oriented  files  (e.g., pipe, FIFO, stream socket), the
       condition that the read/write I/O space is exhausted  can  also  be
       detected  by checking the amount of data read from / written to the
       target file descriptor.  For example, if you call read(2) by asking
       to read a certain amount of data and read(2) returns a lower number
       of bytes, you can be sure of having exhausted the  read  I/O  space
       for  the  file  descriptor.   The  same  is true when writing using
       write(2).  (Avoid this latter technique  if  you  cannot  guarantee
       that  the  monitored file descriptor always refers to a stream-ori‐
       ented file.)
于 2021-02-22T07:04:44.103 回答