par
函数是如何工作的?它的签署是:
par :: a -> b -> b.
但这很奇怪。为什么不是:
par :: (a -> b) -> a -> b
(获取函数,在新线程中执行它并返回结果)?
另一个问题,这是正常的haskell多线程处理吗?
发布于 2014-05-30 12:33:12
par
是用于推测并行性的,并且依赖于懒惰。
您可以推测,在忙于处理a
时,应该计算未评估的b
。
稍后在您的程序中,您可能再次引用a
,它将准备就绪。
下面是一个例子。我们希望把三个数字加在一起。每个数字计算起来都很昂贵。我们可以并行计算它们,然后将它们相加在一起:
main = a `par` b `par` c `pseq` print (a + b + c)
where
a = ack 3 10
b = fac 42
c = fib 34
fac 0 = 1
fac n = n * fac (n-1)
ack 0 n = n+1
ack m 0 = ack (m-1) 1
ack m n = ack (m-1) (ack m (n-1))
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
发布于 2014-05-30 12:36:16
因为我们没有在Haskell中“执行函数”。我们评估值,这就是我们控制处理器活动的方法。par x y
所做的基本上是:在评估结果y
时,运行时也已经对x
进行了预评估,尽管这本身还没有被要求。
请注意,这不一定是目前编写并行代码的最佳方式。查看更新的替代方案,如蒙纳德。您可能想读西蒙·马洛的书。
发布于 2014-06-01 20:25:15
除了以前的回答外,值得指出的是,a
和b
只会被评估为弱头范式(即应用最外层约简或构造函数),因此使用deepseq
强制求值可能是有用的。
在操作语义方面,par
创建了一个火花,它是一个指向雷击(未评估的计算)的指针,并添加到火花池中。这是非常便宜和有可能有数百万火花。线程创建是一种建议,运行时系统可以通过忽略星星之火或将子火花包含在父进程中来决定不将a
转换为线程和修剪超流并行。
您显示的图片可能表明您的代码有问题,在CPU2上执行的线程要做的工作要少得多(负载不平衡)。
https://stackoverflow.com/questions/23954646
复制相似问题