Haskell 中的自动并行性

Kri*_*itz 5 parallel-processing haskell

在haskell中,假设我有一个以下形式的函数调用:foo a b,其中a不依赖于b,反之亦然。看起来它可以自动检测到a并且b可以并行评估,但在 GHC 中似乎并非如此。相反,需要使用像 need 这样的结构par来表示可以并行评估的内容。

那么,为什么 Haskell 中的并行化不能自动发生呢?或者,如果已经存在,为什么还会par存在这样的结构?

Don*_*art 5

似乎可以自动检测到a和b可以并行计算

正如您所暗示的,通过查看值之间的依赖关系可以自动检测并行性。当不涉及副作用时,这尤其容易。

问题在于知道何时停止并行。

这一切都归结为在编译时了解运行时将发生多少工作。对于任意代码来说,这些“成本模型”通常很难实现。

考虑:

  • (+)是否应该并行评估每个参数?
  • 每张地图都应该并行评估吗?

如果我们天真地并行化所有独立计算,编译器将生成大量并行任务。数百万或数十亿个并行表达式。我们的 8 或 16 核机器还没有准备好处理这些问题。

单纯的并行化会导致大量的开销,试图将工作安排到少量可用的并行硬件上。

纯程序中的并行量与可用硬件之间的差距迫使我们做出一些妥协。即:

  1. 用户注释的提示,表明哪些事情并行执行的成本足够高
  2. 具有清晰成本模型的语言子集,因此编译器可以很智能。

第一种形式的示例——用户提示——par注释Parmonad。关于第二种——自动并行子语言——请参阅Data Parallel Haskell

  • 这个答案*假设*要么(a)有一个非常幼稚的运行时环境,盲目地生成任务和/或(b)必须在编译时知道必须在哪里引入多少并行性。它并没有指出自动并行性(在 Haskell 中)只是一个未解决的问题,而不是一个“无法解决”的问题。(a) 为什么工作线程(固定池)不能根据现有线程的运行时堆栈来确定它们可以去哪里并做一些工作?(b) 为什么必须在编译时知道必须发生并行化的地方? (3认同)
  • 我不明白为什么我们不能用 C/C++ 编写 Haskell 风格的函数(副作用和无状态)程序,而只使用例如 [Cilk](https://en.wikipedia.org/wiki/Cilk)在每个子函数调用上盲目使用“spawn”和“sync”关键字(“foo ab”示例中的“a”和“b”),然后在结果上计算“foo a”b“之前使用“sync” 。这些关键字只是提示,如果所有工作线程都已繁忙,则运行时会忽略它们。似乎是理想的解决方案...... (2认同)