par
声明为:
par :: a -> b -> b
请注意,该论点已被丢弃。为了使用 par ,您需要多次使用相同的表达式等技巧。
如果它的目的是并行执行a和b,为什么不这样定义呢?:
par :: (a, b) -> (a, b)
获取(未评估)表达式的元组并返回相同的表达式 - 虽然它们可能在后台线程上实现。
似乎后一种模型比前者更简单。为什么选择这样的设计?
par
声明为:
par :: a -> b -> b
请注意,该论点已被丢弃。为了使用 par ,您需要多次使用相同的表达式等技巧。
如果它的目的是并行执行a和b,为什么不这样定义呢?:
par :: (a, b) -> (a, b)
获取(未评估)表达式的元组并返回相同的表达式 - 虽然它们可能在后台线程上实现。
似乎后一种模型比前者更简单。为什么选择这样的设计?
在前者中,您可以轻松触发两个以上的计算,
c1 `par` c2 `par` c3 `par` c4 `pseq` something c1 c2 c3 c4
这在后者中会相当麻烦。
您建议的元组版本可以在 Control.Parallel.Strategies 中作为 parTuple2 找到,其类型为:
evalTuple2 :: Strategy a -> Strategy b -> Strategy (a, b)
至于为什么par是这样设计的,par是“更高级别”,正如Real World Haskell第 24 章所讨论的那样,他们并行化了快速排序:
我们代码的这些更改对于我们不需要说的所有事情来说都是显着的。
- 要使用多少个内核。
- 线程之间进行什么通信。
- 如何在可用内核之间分配工作。
- 哪些数据在线程之间共享,哪些是私有的。
- 如何确定所有参与者何时完成。
在A Monad for Deterministic Parallelism中,Marlow、Newton 和 Peyton Jones 写道:
par 运算符是一种有吸引力的语言设计,因为它利用了惰性求值和期货之间的重叠。为了实现惰性求值,我们必须对尚未求值但稍后可能需要其值的表达式进行表示;同样,未来是一种计算,其值正在被并行评估,我们可能会等待。因此,par 被认为是一种机制,用于将惰性计算注释为并行评估可能有利可图,实际上将惰性计算转变为未来