epoll性能

10

请有人帮忙回答有关epoll_wait的问题。

  1. 为了服务于约10万个活动套接字,使用多个调用epoll_wait的线程是否过度?或者仅创建一个线程执行epoll_wait就足够了?

  2. 当只有一个套接字准备好读取数据时,会有多少个线程从epoll_wait中唤醒?我的意思是,会发生2个或更多线程从epoll_wait中唤醒,但其结果事件中具有相同的套接字吗?

  3. 在与许多活动客户端(例如50K+)一起工作的服务器中,组织线程的最佳方法是什么?我认为最好的方法是:1个I/O工作线程 执行epoll_wait和I/O操作。+ 许多数据处理线程 将处理从I/O工作线程收到的数据(可能需要很长时间,例如任何游戏逻辑),并将新数据组合成I/O工作线程发送给客户端。我这种方法正确吗,还是有其他更好的方法?

谢谢Valentin提前。

3个回答

12
  1. 使用 epoll 时,你需要将线程总数设置为你想要用于处理的物理 CPU 核心数(或超线程调度单元)的数量。使用一个线程意味着最多只有一个核心处于活动状态。

  2. 这取决于 epoll 文件描述符的模式。事件可以是“边缘触发”的,这意味着它们只会原子地发生一次,或者是“水平触发”的,这意味着如果缓冲区中有空间,任何调用者都会接收到事件。

  3. 没有足够的信息来确定。我建议根本不要有特殊目的的线程,而是在接收到每个事件的线程中处理其“命令”,以保持简单。但显然这取决于你的应用程序的性质。


所以,如果我理解正确,最好的模式如下:创建与系统中核心数相等的I/O线程数量,并使用ET epoll_wait。每个线程将拥有自己的一部分fd。例如,对于IC2Q处理器,有4个线程。每个线程处理25K个连接,总共100K个。接下来的问题是: 我需要单独的线程来epoll_wait监听套接字并管理新接受的套接字将添加到哪个id子集中吗?在一个线程中使用epoll_ctl添加新接受的fd,而另一个线程正在对此子集进行epoll_wait,这样做是线程安全的吗? - Valentin
2
我会在所有线程中等待所有描述符。除非您知道通过将相关工作隔离到特定的CPU上可以获得缓存效应的胜利,否则进行这种分区通常是一种损失。您最终会使一个CPU饥饿,而另一个CPU仍然有可完成的工作。是的:epoll操作是原子的(尽管显然您需要自己锁定任何自己的簿记)。 - Andy Ross
ET epoll_wait会如何表现?所有线程都会从epoll_wait中唤醒吗?还是只有一个线程?如果我理解正确,ET epoll_wait是原子性的,并且仅对准备好的fd发生一次。例如:我有2个fd和2个线程在等待epoll_wait。1个fd变为就绪状态,只有1个线程将被恢复,如果另一个fd在第一个线程处理第一个fd期间变为就绪状态,则第二个线程将被恢复。Andy,这正确吗? - Valentin
@Valentin(虽然很晚了,但)是的,我相信这是正确的。 - Armin Rigo
2
@Valentin 如果您希望确保每个文件描述符只被唤醒一次,请使用EPOLLONESHOT。EPOLLET也可以实现类似的功能,但没有如此强的保证。这里有更详细的解释。 - Craig M. Brandenburg
这个答案是完全错误的。请查看我的答案以获取详细信息。 - thodg

5

-4

实际上,这是 epoll 的错误用法。

绝对不能在线程之间共享 epoll fd。否则,一个线程可能会在一个 fd 上读取部分传入数据,而另一个线程也可能在同一个 fd 上读取相同的数据,而无法知道哪一部分数据先到达。

只需在每个调用 epoll_wait 的线程中调用 epoll_create。否则,I/O 将会出现问题。


3
在我看来,你似乎把 epoll 文件描述符与实际套接字的文件描述符混淆了。在多个线程中使用 epoll 完全是可行的,事实上,这就是使用它的一个要点。为了避免线程之间的竞争条件,你需要使用 EPOLLONESHOT 或,在更新的内核中,使用 EPOLLEXCLUSIVE这篇优秀的博客详细解释了细节。 - kralyk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接