5

这大约需要 1 秒

(1 to 1000000).map(_+3)

虽然这给出了java.lang.OutOfMemoryError: Java heap space

(1 to 1000000).par.map(_+3)

编辑:

我有标准的 scala 2.9.2 配置。我在 scala 提示符下输入这个。在 bash 我可以看到 [ -n "$JAVA_OPTS" ] || JAVA_OPTS="-Xmx256M -Xms32M"

而且我没有在我的环境中设置 JAVA_OPTS。

100 万个整数 = 8MB,创建两次列表 = 16MB

4

4 回答 4

9

它似乎与 JVM 内存选项存储 Parralel 集合所需的内存肯定有关。例如:

scala> (1 to 1000000).par.map(_+3)

最后是OutOfMemoryError我第三次尝试评估它,而

scala> (1 to 1000000).par.map(_+3).seq

从来没有失败过。问题不在于计算,而是并行集合的存储。

于 2012-06-01T09:56:21.490 回答
3

失败的几个原因:

  1. 并行集合不是专门的,因此对象被装箱。这意味着您不能将元素的数量乘以 8 来获得内存使用情况。
  2. 使用map意味着将范围转换为向量。对于并行向量,尚未实现有效的串联,因此合并由不同处理器产生的中间向量通过复制进行 - 需要更多内存。这将在未来的版本中解决。
  3. REPL 存储以前的结果 - 在每一行中评估的对象保留在内存中。
于 2012-06-01T12:01:20.357 回答
2

这里有两个问题,存储并行集合所需的内存量和“通过”并行集合所需的内存量。

可以看出这两行之间的区别:

(1 to 1000000).map(_+3).toList
(1 to 1000000).par.map(_+3).toList

REPL 存储评估的表达式,记住。在我的 REPL 上,我可以在内存不足之前执行这 7 次。通过并行执行暂时使用额外的内存,但是一旦执行 toList,额外的使用量就会被垃圾收集。

(1 to 100000).par.map(_+3)

返回 ParSeq[Int](在本例中为 ParVector),它比普通 Vector 占用更多空间。这个我可以在内存不足之前执行 4 次,而我可以执行这个:

(1 to 100000).map(_+3)

在我用完内存之前有 11 次。所以并行集合,如果你把它们放在身边,会占用更多的空间。

作为一种解决方法,您可以List在返回它们之前将它们转换为更简单的集合,例如 a。

至于为什么并行集合占用这么多空间,为什么还要引用这么多东西,我不知道,但我怀疑views[*],如果你认为这是一个问题,请提出一个问题

[*] 没有任何真实证据。

于 2012-06-01T12:13:18.927 回答
0

我也有同样的情况,但是使用 ThreadPool 似乎可以解决我的问题:

  val threadPool = Executors.newFixedThreadPool(4)
  val quadsMinPar = quadsMin.par
  quadsMinPar.tasksupport = new ThreadPoolTaskSupport(threadPool.asInstanceOf[ThreadPoolExecutor])

大型集合的 ForkJoin 可能会创建太多线程。

于 2015-01-12T14:29:36.303 回答