【问题标题】:Why does scala.io.Source use all cores?为什么 scala.io.Source 使用所有内核?
【发布时间】:2014-07-01 17:04:12
【问题描述】:

我注意到以下代码使用多个线程并在读取文件时使所有 CPU 内核保持约 100% 忙碌。

scala.io.Source.fromFile("huge_file.txt").toList

我假设以下是相同的

scala.io.Source.fromFile("huge_file.txt").foreach

我在开发机器 (OS X 10.9.2) 上的 Eclipse 调试器下将此代码作为单元测试中断,并显示以下线程:ma​​in、ReaderThread、3 Daemon System Threadhtop 显示如果我在 24 核服务器机器(ubuntu 12)的 scala 控制台中运行它,所有线程都处于忙碌状态。

问题:

  1. 如何限制此代码使用 N 个线程?
  2. 为了了解系统性能,您能否向我解释一下在 io.Source 中这是什么、为什么以及如何完成的?阅读源代码没有帮助。
  3. 我假设每一行都是按顺序读取的;但是,由于它使用多个线程,所以foreach 是否在多个线程中运行?我的调试器似乎告诉我代码仍在主线程中运行。

任何见解将不胜感激。

【问题讨论】:

  • 您确定没有在所有线程上看到垃圾收集器活动吗?
  • 我不这么认为,因为所有 24 个内核在列出列表时都接近 100%。我相信临时对象清理不应该造成如此沉重的负担。
  • 也许你应该确定-XX:+UseSerialGC
  • 当您调用toList 时,您将这个非常大的文件强制存储到内存中,这绝不是一个好主意,并且可能是您在计算机上看到的所有抖动的原因。我看不到任何实际的用例,其中将一个非常大的文件完全读入内存是一个好主意。这就是为什么你从 Iterator 开始并且必须进行显式调用以强制它进入列表
  • 不是骗人的,但人们经常问这个问题stackoverflow.com/q/23007646/1296806

标签: multithreading scala io parallel-processing


【解决方案1】:

按照建议,我将我的发现放在这里。

我使用以下内容来测试我的虚拟代码有和没有-J-XX:+UseSerialGC 选项

$ scala -J-XX:+UseSerialGC
scala> var c = 0
scala> scala.io.Source.fromFile("huge_file.txt").foreach(e => c += e)

在我使用该选项之前,我的服务器机器中的所有 24 个内核在文件读取期间都处于忙碌状态。选项后只有两个线程忙。

这是我在我的开发机器上捕获的内存配置文件,而不是服务器。我首先执行 GC 以获取基线,然后我多次运行上述代码。伊甸空间会定期清理。内存摆动约为 20M,而我读取的较小文件约为 200M,即io.Source 每次运行都会创建 10% 的临时对象。

此特性会在共享系统中造成麻烦。这也将限制我们一次处理多个大文件。这会对内存、i/o 和 CPU 使用造成压力,我无法将我的代码与其他生产作业一起运行,而是单独运行以避免对系统造成影响。

如果您知道在真正的共享生产环境中处理这种情况的更好方法或建议,请告诉我。

【讨论】:

  • 尝试使用-XX:ParallelGCThreads=n将GC线程数限制在更合理的数量。
猜你喜欢
  • 2016-09-10
  • 2011-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多