与scala未来的垃圾收集

时间:2012-10-16 18:58:41

标签: scala future

我有一堆我正在尝试并行处理的xml文件。我使用未来的scala代码(2.9.2)开始很好,但最终吃掉了我机器上32G的近100%。当我按顺序执行此操作时,这不会发生,因此我猜测使用scala期货时垃圾收集存在问题。

这是我的代码的精简版本。谁能告诉我什么是错的?

val filenameGroups = someStringListOfFilepaths.grouped(1000).toStream
val tasks = filenameGroups.map {
  fg =>
    scala.actors.Futures.future {
      val parser = new nu.xom.Builder() // I'm using nu.xom. Not sure it matters.
      fg.map {
        path => {
          val doc = parser.build(new java.io.File(path))
          val result = doc.query(some xpath query)
          result
        }
      }.toList
    }
}

val pairs = tasks.par.flatMap(_.apply)

ETA:好的,我解决了这个问题,但我仍然不知道为什么这会产生影响。

我抽象了内循环中的大部分代码然后重新编写它。从未来撤出解析器实例化。内存使用率现在保持在17%不变。有没有人知道为什么会产生影响?

以下是我所做的简化版本:

def process(arglist...) = yada

val tasks = filenameGroups.map {
  fg =>
    val parser = new nu.xom.Builder()
    scala.actors.Futures.future {
      process(fg, parser)
    }
}

val pairs = tasks.par.flatMap(_.apply)

1 个答案:

答案 0 :(得分:2)

期货无法真实地预测您想要多少线程或您的计算将占用多少内存,因此通常您有责任将适当的序列化计算放在适度数量的期货中。特别是,如果您使用的是8核计算机,则可能不希望将组小于someStringListOfFilepaths.length/8(如果您的文件太大而不能同时存在8个内存,则会更少)。您可以使用标准的Java技巧来检查核心数量covered on SO以及许多其他地方,如果您想在每台计算机上进行扩展而不必考虑它。 (在这种情况下,也可能要检查Runtime.getRuntime.maxMemory,以防你在拥有大量内核且RAM不多(或没有为VM分配)的机器上。)

(顺便提一下,在你的最小例子中,既有懒惰也有未来,但是懒惰对你没有任何作用。期货在创建时已经没有运行,因此延迟期货的实例化可能对你没有任何帮助。 )

另外,请注意,如果你有200k文件,你将得到200k的结果,并且根据结果的大小,可能会占用大量内存。可能不是32G,但谁知道文件中有什么?