我在Haskell学习并行性。我看过这段代码:
runEval $ do
a <- rpar (f x)
b <- rpar (f y)
rseq a
rseq b
return (a,b)
它在性能和开销方面的区别是什么?
let a = f x
let b = f y
(a, b)
即,根本不使用Eval
。对我来说,第二个具有相同的性能和更少的开销。
答案 0 :(得分:6)
完全取决于f
的作用。如果f
花费很长时间让您的系统进行计算,并且您的系统有一个备用CPU核心,则并行版本将更快完成。
如果f
像f n = n + 1
那样微不足道,那么当然标准的单线程版本会更快。创建Haskell线程的开销相当低,但 低。 (如果你只有一个执行上下文,那么当然没有任何意义)。
请注意,如果我们将开销定义为“系统执行与计算结果无直接关系的工作”,那么第一个版本总是会有更多的“开销”。但是,如果您同时评估f x
和f y
,即使系统在开销上“浪费”了一些执行资源,您也可能会更快完成。我们可能将并行版本的运行时间近似为:
maximum(time for f x, time for f y) + overhead
标准版的运行时间为:
time for f x + time for f y
因此,如果两个f
调用的较小比并行化开销花费的时间更长,那么并行版本是值得的。
当然,实际上它可能要复杂得多。一个这样的问题:如果f x
和f y
共享对同一个thunk的引用,那么标准顺序版本完全共享工作,而并行版本可能会意外地浪费时间让两个线程执行thunk。特别是如果f x
和f y
的大部分工作实际减少了thunk以使f
准备好应用,那么你就不会“真正”并行化这项工作根本就是(或多或少地竞争两个线程,看看哪个先完成)。
最终,您需要使用度量和判断来决定应用并行性的位置。这不是你可以盲目添加并自动获得好处的东西(否则编译器会为你做的)。
但如果你尝试并行运行两个非常简单的计算,它肯定不会给你任何好处。如果您只是在玩并行性以了解其工作原理,请尝试编写一个功能f
来完成足够的工作,使您的第二个版本至少需要几秒钟才能运行,然后再看如果并行版本更快。