scala - scala future 的垃圾收集

标签 scala future

我有一堆要并行处理的 xml 文件。我使用 future 的 scala 代码 (2.9.2) 开始时运行良好,但最终耗尽了我机器上 32G 内存的近 100%。当我按顺序执行此操作时不会发生这种情况,所以我猜测在使用 scala futures 时垃圾收集有问题。

这是我的代码的精简版。谁能告诉我哪里出了问题?

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)

预计到达时间:好的,我解决了这个问题,但我仍然不知道为什么这会产生影响。

我提取了内部循环中的大部分代码,然后重新运行它。并从 future 中取出解析器实例化。内存使用率现在稳定在 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)

最佳答案

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

(顺便说一句,在您的最小示例中,既有懒惰又有 future ,但懒惰对您没有任何作用。 future 在创建时已经没有运行,因此延迟 future 的实例化可能对您没有任何帮助。 )

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

关于scala - scala future 的垃圾收集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12921619/

相关文章:

C++ 稍后从线程函数获取返回值

dictionary - Flutter - 如何在我 future builder 文本小部件中获得值(value)返回

Scala:如何强制将整数包装为对象?

scala - 我们不能在 map 函数中使用 sparkContext 吗?

java - Guava 缓存refreshAfterWrite困惑

java - 等待取消的 future 真正完成

java - 不同线程数的结果不同

scala - 用于聊天和类似 Twitter 的应用程序的并发程序语言

scala - 了解 Apache Spark RDD 任务序列化

scala - Scala Future 的优雅处理[任一]]