提升 Asio 单线程性能

Posted

技术标签:

【中文标题】提升 Asio 单线程性能【英文标题】:Boost Asio single threaded performance 【发布时间】:2013-02-25 18:11:04 【问题描述】:

我正在实现需要维护大量(100K 或更多)长期连接的自定义服务器。服务器只是在套接字之间传递消息,它不做任何严肃的数据处理。消息很小,但其中许多消息每秒都会接收/发送。减少延迟是目标之一。我意识到使用多核不会提高性能,因此我决定通过调用io_service 对象的run_onepoll 方法在单线程中运行服务器。无论如何,多线程服务器将更难实现。

可能的瓶颈是什么?系统调用、带宽、完成队列/事件多路分解?我怀疑调度处理程序可能需要锁定(由 asio 库在内部完成)。是否可以在 boost.asio 中禁用队列锁定(或任何其他锁定)?

编辑:相关问题。多线程时系统调用性能会提高吗?我的感觉是,因为系统调用是由内核原子/同步的,所以添加更多线程不会提高速度。

【问题讨论】:

如果您在一个线程中运行所有内容,则不需要任何(手写)锁。 使用多核可能会提高性能 - 请参阅 cmeerw.org/blog/748.html#748 和 cmeerw.org/blog/746.html#746 了解我去年所做的一些基准测试。 【参考方案1】:

您可能想阅读几年前的my question,我在为Blue Gene/Q supercomputer 开发系统软件时第一次调查Boost.Asio 的可扩展性时问过它。

扩展到 100k 或更多连接应该不是问题,但您需要注意明显的资源限制,例如打开文件描述符的最大数量。如果您还没有阅读开创性的C10K paper,我建议您阅读它。

在使用单个线程和单个io_service 实现应用程序后,我建议调查调用io_service::run() 的线程池,然后才调查将io_service 固定到特定线程和/或cpu。 Asio 文档中包含所有这三种设计的多个示例,以及关于 SO 的several questions 提供更多信息。请注意,当您引入多个调用io_service::run() 的线程时,您可能需要实现strands 以确保处理程序具有对共享数据结构的独占访问权限。

【讨论】:

【参考方案2】:

使用 boost::asio,您可以以大致相同的开发成本编写单线程或多线程服务器。您可以将单线程版本编写为第一个版本,然后根据需要将其转换为多线程。

通常,boost::asio 的唯一瓶颈是 epoll/kqueue 反应器在互斥体中工作。因此,只有一个线程同时进行 epoll。如果您有多线程服务器,这可能会降低性能,该服务器提供大量非常小的数据包。但是,无论如何,它应该比普通的单线程服务器更快。

现在谈谈你的任务。如果您只想在连接之间传递消息-我认为它必须是多线程服务器。问题是系统调用(接收/发送等)。一条指令很容易为 CPU 执行,但任何系统调用都不是非常“轻量级”的操作(一切都是相对的,但相对于您任务中的其他工作)。所以,单线程你会得到很大的系统调用开销,这就是我推荐使用多线程方案的原因。

另外,您可以分离 io_service 并使其作为“每个线程的 io_service”习语工作。我认为这必须提供最佳性能,但它有缺点:如果 io_service 之一将获得太大的队列 - 其他线程将无济于事,因此某些连接可能会变慢。另一方面,使用单个 io_service - 队列溢出会导致较大的锁定开销。你所能做的——做这两种变体并测量带宽/延迟。实现这两种变体应该不会太难。

【讨论】:

以上是关于提升 Asio 单线程性能的主要内容,如果未能解决你的问题,请参考以下文章

使用 libevent 或 boost::asio 的单线程中的多个 tcp 连接。这是可能的?

单线程与线程池的性能对比

谷歌计算引擎提高单线程性能

如何提升爬虫的性能

单线程Boost死锁

使用多线程时性能几乎没有提升