提升 Asio 单线程性能
Posted
技术标签:
【中文标题】提升 Asio 单线程性能【英文标题】:Boost Asio single threaded performance 【发布时间】:2013-02-25 18:11:04 【问题描述】:我正在实现需要维护大量(100K 或更多)长期连接的自定义服务器。服务器只是在套接字之间传递消息,它不做任何严肃的数据处理。消息很小,但其中许多消息每秒都会接收/发送。减少延迟是目标之一。我意识到使用多核不会提高性能,因此我决定通过调用io_service
对象的run_one
或poll
方法在单线程中运行服务器。无论如何,多线程服务器将更难实现。
可能的瓶颈是什么?系统调用、带宽、完成队列/事件多路分解?我怀疑调度处理程序可能需要锁定(由 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()
的线程时,您可能需要实现strand
s 以确保处理程序具有对共享数据结构的独占访问权限。
【讨论】:
【参考方案2】:使用 boost::asio,您可以以大致相同的开发成本编写单线程或多线程服务器。您可以将单线程版本编写为第一个版本,然后根据需要将其转换为多线程。
通常,boost::asio 的唯一瓶颈是 epoll/kqueue 反应器在互斥体中工作。因此,只有一个线程同时进行 epoll。如果您有多线程服务器,这可能会降低性能,该服务器提供大量非常小的数据包。但是,无论如何,它应该比普通的单线程服务器更快。
现在谈谈你的任务。如果您只想在连接之间传递消息-我认为它必须是多线程服务器。问题是系统调用(接收/发送等)。一条指令很容易为 CPU 执行,但任何系统调用都不是非常“轻量级”的操作(一切都是相对的,但相对于您任务中的其他工作)。所以,单线程你会得到很大的系统调用开销,这就是我推荐使用多线程方案的原因。
另外,您可以分离 io_service 并使其作为“每个线程的 io_service”习语工作。我认为这必须提供最佳性能,但它有缺点:如果 io_service 之一将获得太大的队列 - 其他线程将无济于事,因此某些连接可能会变慢。另一方面,使用单个 io_service - 队列溢出会导致较大的锁定开销。你所能做的——做这两种变体并测量带宽/延迟。实现这两种变体应该不会太难。
【讨论】:
以上是关于提升 Asio 单线程性能的主要内容,如果未能解决你的问题,请参考以下文章