Boost Asio 单线程性能提升

13
我正在实现一个自定义服务器,需要维护非常大量(100K或更多)的长连接。服务器只是在套接字之间传递消息,不进行任何严格的数据处理。消息很小,但每秒接收/发送许多消息。减少延迟是其中一个目标。我意识到使用多个核心不会提高性能,因此我决定通过调用io_service对象的run_one或poll方法在单个线程中运行服务器。无论如何,多线程服务器将更难实现。
可能的瓶颈是什么?系统调用、带宽、完成队列/事件多路复用?我怀疑分配处理程序可能需要锁定(这是由asio库内部完成的)。是否可以在boost.asio中禁用事件队列锁定(或其他任何锁定)?
编辑:相关问题。系统调用性能是否会随着多线程而提高?我的感觉是,因为系统调用是由内核原子/同步的,所以添加更多线程不会提高速度。

1
如果你在一个线程中运行所有东西,就不需要任何(手写)锁。 - Arne Mertz
3
使用多个内核可能会提高性能-参见我去年进行的一些基准测试 http://cmeerw.org/blog/748.html#748 和 http://cmeerw.org/blog/746.html#746。 - cmeerw
2个回答

18
你可能想阅读我几年前提出的我的问题,当时我正在为Blue Gene/Q超级计算机开发系统软件时调查Boost.Asio的可扩展性。
扩展到10万个或更多的连接不应该是问题,但你需要注意明显的资源限制,例如最大打开文件描述符数量。如果你还没有阅读过经典的C10K论文,我建议你阅读一下。

当你使用单个线程和单个io_service实现应用程序后,我建议研究使用线程池调用io_service::run(),然后再研究将io_service固定到特定的线程和/或CPU上。Asio文档中包含了这三种设计的多个示例,并且有几个问题在SO上提供更多信息。请注意,当您引入多个线程调用io_service::run()时,您可能需要实现strand来确保处理程序对共享数据结构具有独占访问权限。


11
使用boost::asio,您可以以大致相同的开发成本编写单线程或多线程服务器。您可以将单线程版本作为第一个版本编写,然后根据需要将其转换为多线程版本。
通常,boost::asio的瓶颈只在于epoll/kqueue反应器正在互斥体中运行。因此,同一时间只有一个线程执行epoll操作。如果您有一个为许多非常小的数据包提供服务的多线程服务器,则可能会降低性能。但是,在我看来,它仍然应该比普通的单线程服务器快。
现在谈谈您的任务。如果您只想在连接之间传递消息-我认为这必须是多线程服务器。问题在于系统调用(recv/send等)。指令对于CPU来说非常容易执行,但任何系统调用都不是非常“轻量级”的操作(相对而言,但相对于您任务中的其他工作而言)。因此,使用单个线程会产生很大的系统调用开销,这就是我建议使用多线程方案的原因。
此外,您可以将 io_service 分离并将其作为“每个线程的io_service”成语来使用。我认为这必须提供最佳性能,但它也有缺点:如果其中一个io_service的队列变得太大,其他线程将无法帮助它,因此某些连接可能会减速。另一方面,使用单个io_service - 队列溢出可能会导致大量锁定开销。您可以做的就是执行两种变体并测量带宽/延迟。实现这两种变体应该不太困难。

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