【问题标题】:TCP Server w/ boost::asio, scalability of thread pool vs stackless coroutines带 bo​​ost::asio 的 TCP 服务器,线程池与无堆栈协程的可扩展性
【发布时间】:2012-05-20 04:36:29
【问题描述】:

我正在构建一个基于 TCP 的守护进程,用于 HTTP 请求的预处理/后处理。客户端将连接到 Apache HTTPD(或 IIS),并且自定义 Apache/IIS 模块会将请求转发到我的 TCP 守护程序以进行进一步处理。我的守护进程需要扩展(但不是扩展)以处理大量流量,并且大多数请求都是小而短暂的。守护进程将使用 C++ 构建,并且必须是跨平台的。

我目前正在研究 boost asio 库,这看起来很自然。但是,我无法理解无堆栈协程与线程池模式的优点。具体来说,我在这里查看 HTTP 服务器示例 #3 和 HTTP 服务器示例 #4:http://www.boost.org/doc/libs/1_49_0/doc/html/boost_asio/examples.html

尽管我进行了所有的谷歌搜索,但我无法完全理解无堆栈协程服务器的优点,以及它相对于多核系统上的线程池服务器的性能。

根据我的要求,两者中哪一个最合适,为什么?请随意“降低”您对无堆栈协同程序想法的回答,我在这里仍然不稳定。谢谢!

编辑:讨论的另一个随机想法/关注点: Boost HTTP 服务器示例 #4 被描述为“使用无堆栈协程实现的单线程 HTTP 服务器”。好的,所以它完全是单线程的(对吗?即使在父进程“分叉”给子进程之后?参见示例 #4 中的 server.cpp)……单线程会成为多核系统的瓶颈吗?我假设任何阻塞操作都会阻止所有其他请求执行。如果确实如此,为了最大限度地提高吞吐量,我正在考虑一个基于协程的接收数据异步事件,一个用于我的内部阻塞任务的线程池(以利用多核),然后是一个异步发送和关闭连接机制。同样,可扩展性至关重要。有什么想法吗?

【问题讨论】:

  • Query:我想我理解“扩大规模”。什么是“向外扩展”?
  • 有些人发现协程方法更易于阅读/实现,因为代码是从上到下阅读的。它们更适合流式解析,因为一旦输入中断后再次开始使用流,您就不必担心从上次中断的地方继续。
  • @avid -- 谢谢,我在 boost HTTP 服务器示例 #4 中看到了他们是如何使用请求解析器做到这一点的。毫无疑问,这非常好,但我更关心性能而不是编码/实现的容易程度。您对此有何看法?
  • @Rob - 通过“横向扩展”,我的意思是添加额外的机器并在它们之间分配负载(我认为我不需要;我的用户将添加另一个 Web 服务器节点和另一个我的应用在后台的实例,我的应用不需要支持网络农场)
  • @TomC:是的。无堆栈协程示例上下文中的“分叉”与线程无关。它看起来像传统的 fork 操作,但协程不是线程。我没有使用 asio 协程的东西,但我认为它主要是为了可读性,即使事件驱动的代码更具可读性。这些并不是真正的提升的一部分,它们只是在 asio 示例中,在此处查看更多信息:blog.think-async.com/2009/07/…

标签: c++ multithreading boost boost-asio coroutine


【解决方案1】:

我最近研究了 boost.asio 在多核机器上的可扩展性。到目前为止的主要结论是它确实引入了开销、锁争用和额外的上下文切换(至少在 Linux 上),请参阅我关于这些主题的一些博客文章:

我还在 asio 邮件列表上创建了一个线程,以检查我没有遗漏任何明显的内容,请参阅 http://comments.gmane.org/gmane.comp.lib.boost.asio.user/5133

如果您主要关心的是性能和可扩展性,那么恐怕没有明确的答案 - 您可能需要进行一些原型设计并查看性能。

如果您有任何阻塞操作,那么您肯定希望使用多线程 - 另一方面,上下文切换和锁争用会降低多线程的性能(至少您必须非常小心)。

编辑:只是为了澄清无堆栈协程的东西:它本质上只是一些语法糖,使异步 API 看起来更像顺序/阻塞调用。

【讨论】:

  • 感谢您分享您的专业知识,我一定会在构建服务器时深入挖掘您的博客和示例代码。很棒的 ASIO 线程。似乎我只需对几个不同的实现进行基准测试并从那里开始。嘿,你的 ASIO 线程中有人问你是否使用了协程函数,但没有看到回复。您是否打算对此进行分析?感谢您的帮助!
  • 您对 Tom 的基准测试和分析结果如何?我很想知道你去哪里了,因为我也在玩这个。
  • @Homer6 -- 在确认 boost 示例 #4 确实仅限于单核后,我重新构建了我的应用程序。即使不是,在我的情况下,在 Web 服务器的线程中运行比创建我自己的池更有意义。所以,至少现在,我已经放弃了这个想法,并且没有进一步追求它。抱歉,我无法提供更多帮助!
【解决方案2】:

由于难以预测参考局部性、CPU 指令缓存、调度延迟等的相对影响,您需要测量影响以确定实际会发生什么。

如果您想进行启发式猜测,请考虑使用堆栈大小为 Sn 个线程,无论堆栈大小如何,每个线程总是占用 nS 个字节每个线程实际使用的空间。如果这使您跨越页面边界,则可能会显着降低性能。

【讨论】:

  • 谢谢 Mike,我想我问的更多是理论上的“无堆栈协程比线程池性能更高吗?”还是我错误地将两个独立的概念混为一谈?
  • @TomC:如果您使用的是 Windows,请选择线程切换最少的选项。根据我的经验,精心编写的协程会减少缓存抖动。如果您长时间阻塞,则抖动就不那么明显了。
  • @JimR:感谢您的提示。我计划同时针对 Windows 和 *nix,因此非常感谢您的建议
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-14
  • 1970-01-01
  • 1970-01-01
  • 2015-05-12
  • 1970-01-01
  • 2014-05-23
  • 1970-01-01
相关资源
最近更新 更多