【问题标题】:Are thread pools needed for pure Haskell code?纯 Haskell 代码是否需要线程池?
【发布时间】:2013-03-03 22:25:11
【问题描述】:

Real World Haskell, Chapter 28, Software transactional memory 中,开发了一个并发的网络链接检查器。它获取网页中的所有链接,并用 HEAD 请求点击它们中的每一个,以确定链接是否处于活动状态。本程序采用并发的方式构建,声明如下:

我们不能简单地为每个 URL 创建一个线程,因为如果(如我们所料)大多数链接都是实时且响应式的,这可能会使我们的 CPU 或网络连接负担过重。相反,我们使用固定数量的工作线程,这些线程从队列中获取要下载的 URL。

我不完全理解为什么需要这个线程池而不是为每个链接使用forkIO。 AFAIK,Haskell 运行时维护一个线程池并适当地安排它们,所以我看不到 CPU 过载。此外,在a discussion about concurrency on the Haskell mailing list 中,我发现以下语句朝着相同的方向发展:

在 Haskell 中没有意义的一个范例是工作线程(因为 RTS 就是这样做的 为了我们);而不是获取一个工人,而只是 forkIO。

线程池是仅网络部分需要还是有 CPU 原因?

【问题讨论】:

  • 需要池来控制并发级别并对其进行管理。您可能忘记了实际考虑因素。Haskell 运行时确实非常擅长维护 Haskell 空间线程 - 它们非常轻量级,您可以毫无问题地生成数千个线程。但是,当您获取 10 万个 url 的列表并且一个接一个地 forkIO 没有“池”时会发生什么?您可能会建立成千上万的连接。许多会超时,您的系统将用完文件描述符,并且您可能会在尝试处理结果时用完 RAM。

标签: multithreading haskell


【解决方案1】:

我想,核心问题是网络方面。如果您有 10,000 个链接和每个链接的 forkIO,那么您可能有 10,000 个尝试一次打开的套接字,这取决于您的操作系统的配置方式,甚至可能都不可能,效率要低得多。

然而,我们拥有跨多个操作系统线程“虚拟”调度的绿色线程这一事实并不意味着我们可以随机分配工作而不考虑 CPU 使用情况。这里的问题不在于 CPU 本身的调度不会为我们处理,而是上下文切换(甚至是绿色切换)会花费周期。如果每个线程处理不同的数据,则需要将该数据拉入 cpu。如果有足够的数据,这意味着将东西拉入和拉出 cpu 缓存。即使没有,这也意味着将内容从缓存中拉到寄存器等。

即使一个问题是微不足道的平行问题,实际上永远将其分解得尽可能小并尝试“一次性”完成它是正确的想法。

【讨论】:

  • 哈哈!看起来我们在完全相同的时间(在 15 秒内)评论/回答了!
  • 在单线程中排队时也需要将数据从缓存中拉到寄存器中。我觉得在这种情况下线程管理开销更重要。
猜你喜欢
  • 1970-01-01
  • 2021-06-16
  • 1970-01-01
  • 1970-01-01
  • 2018-09-13
  • 1970-01-01
  • 2010-11-16
  • 2016-05-08
  • 1970-01-01
相关资源
最近更新 更多