垃圾收集与斯卡拉的未来

  • 本文关键字:未来 scala future
  • 更新时间 :
  • 英文 :


我有一堆xml文件,我正在尝试并行处理。我使用 future 的 scala 代码 (2.9.2) 开始时很好,但最终几乎 100% 吃掉了我机器上 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)

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

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

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

最新更新