我非常天真地尝试使用Scala .par,结果证明比非并行版本要慢得多。对此有何解释?
注意:问题不在于提高速度,而在于理解为什么这种对.par的天真使用不能立即提高速度。
注2:计时方法:我用N= 10000运行了这两种方法。第一个大约在20多秒后返回。第二个是我在3分钟后杀死的。一点也不接近。如果让它运行更长时间,我会遇到Java堆空间异常。
def pi_random(N: Long): Double = {
val count = (0L until N * N)
.map { _ =>
val (x, y) = (rng.nextDouble(), rng.nextDouble())
if (x*x + y*y <= 1) 1 else 0
}
.sum
4 * count.toDouble / (N * N)
}
def pi_random_parallel(N: Long): Double = {
val count = (0L until N * N)
.par
.map { _ =>
val (x, y) = (rng.nextDouble(), rng.nextDouble())
if (x*x + y*y <= 1) 1 else 0
}
.sum
4 * count.toDouble / (N * N)
}发布于 2018-04-13 00:56:58
如果不做一些实际的分析,很难确定,但我有两个理论:
首先,您可能会失去Range类的一些好处,特别是几乎为零的内存使用率。当您执行(0L until N * N)时,您将创建一个Range对象,该对象是惰性的。它实际上不会创建包含该范围内每个数字的任何对象。我想map也不知道。而且sum一次计算并相加一个数字,所以也几乎不分配任何内存。
我不确定ParRange是否也是如此。似乎它必须为每个拆分分配一些数量,并且在调用map之后,它可能必须在内存中存储一些中间结果,因为“相邻的”拆分等待另一个拆分完成。尤其是堆空间异常让我认为情况就是这样。所以你会在GC之类的事情上浪费很多时间。
其次,到目前为止,对rng.nextDouble的调用可能是该内部函数中开销最大的部分。但我相信java和scala的Random类本质上都是单线程的。它们在内部同步和阻塞。所以不管怎样,你不会从并行中获得那么多,实际上会损失一些开销。
https://stackoverflow.com/questions/49801698
复制相似问题