multithreading - Haskell 中的半显式并行性

标签 multithreading parallel-processing haskell graph-reduction

我正在阅读 Haskell 中的半显式并行性,并有些困惑。

par::a -> b -> b

人们说这种方法允许我们通过并行评估 Haskell 程序的每个子表达式来自动进行并行化。但是这种方法有以下缺点:

1)它创建了太多的工作小项目,无法有效安排。据我了解,如果对 Haskell 程序的每一行都使用 par 函数,它会创建太多线程,根本不实用。那正确吗?

2) 使用这种方法,并行性受到源程序中数据依赖性的限制。如果我理解正确,这意味着每个子表达式都必须是独立的。就像,在 par 函数中,a 和 b 必须是独立的。

3) Haskell 运行时系统不一定创建线程来计算表达式 a 的值。相反,它会创建一个 Spark ,它有可能在与父线程不同的线程上执行。

所以,我的问题是:最后运行时系统会创建一个线程来计算 a 吗?或者如果需要表达式a来计算表达式b,系统会创建一个新线程来计算a?否则,它不会。这是真的?

我是 Haskell 的新手,所以也许我的问题对你们所有人来说仍然是基本的。感谢您的回答。

最佳答案

par您提到的组合器是 Glasgow parallel Haskell 的一部分(GpH) 实现了半显式并行,但这意味着它不是完​​全隐式的,因此不提供自动并行化。程序员仍然需要识别被认为值得并行执行的子表达式,以避免您在 1) 中提到的问题。

此外,注释不是规定性的(例如 C 中的 pthread_create 或 Haskell 中的 forkIO)而是建议性的,这意味着运行时系统最终决定是否并行计算子表达式。这提供了额外的灵活性和动态粒度控制的方式。另外,所谓的Evaluation Strategies已被设计为抽象超过 parpseq并将协调规范与计算分开。例如,一个策略 parListChunk允许对列表进行分块并强制其为弱头范式(这是需要一些严格的情况)。

2) 并行性受到数据依赖性的限制,因为计算定义了图的缩减方式以及在哪个点需要进行哪些计算。并不是每个子表达式都必须是独立的。例如E1 par E2返回E2的结果,这意味着有用,E1的某些部分需要在E2中使用,因此E2依赖于E1。

3) 由于 GHC 特定的术语,这里的图片有点困惑。有能力(或 Haskell 执行上下文)实现并行图缩减并分别维护一个 Spark 池和一个线程池。通常每个内核有一个 Capability(可以被认为是 OS 线程)。在连续体的另一端有 Spark ,它们基本上是指向图中尚未评估的部分的指针(thunks)。并且有线程(实际上是某种任务或工作单元),因此要并行评估,需要将 Spark 转换为线程(它具有所谓的线程状态对象,该对象包含必要的执行环境并允许 thunk并行评估)。在这些结果到达之前,thunk 可能取决于其他 thunk 和块的结果。这些线程比 OS 线程轻得多,并且被多路复用到可用的 Capablities 上。

因此,总而言之,运行时甚至不必创建轻量级线程来评估子表达式。顺便说一下,随机工作窃取用于负载平衡。

这是一种非常高级的并行方法,可以通过设计避免竞争条件和死锁。同步是通过图缩减隐式调节的。一个不错的立场声明进一步讨论 Why Parallel Functional Programming Matters .有关幕后抽象机器的更多信息,请查看 Stackless Tagless G-Machine并查看 Haskell Execution Model 上的注释在 GHC wiki 上(通常是与源代码一起的最新文档)。

关于multithreading - Haskell 中的半显式并行性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18562112/

相关文章:

python - 如何并行运行函数?

c - 是否应该将 "initCount"变量声明为 "volatile"?

java - 部分线程安全是否使 Java 类线程安全?

在 AWS 上运行 r 模型 - 多个 vCPU 是否像多核系统一样运行?

haskell - 检查 Haskell 程序本身的内存和 CPU 使用情况

haskell - 如何声明一个参数可以是 (Int, Int) 或 Maybe (Int, Int) 的函数?

java - 从不同线程从磁盘读取可以优化程序吗?

multithreading - TParallel.为了性能

haskell - 书写重叠功能

r - 即使数据很小 : Error in mcfork() : unable to fork, 可能的原因:无法分配内存