Scala Concurrency减速

时间:2009-12-07 16:29:03

标签: scala concurrency

我这样做的前提是我是一个相对的Java / Scala新手,所以我不排除有一些明显我不做的事情。

我有一个Scala应用程序,它通过Hibernate连接到MySQL数据库。该应用程序旨在处理大量数据,大约2,750,000条记录,因此我尝试尽可能地优化它。

它在我的工作站上运行,这是一台配备6Gb RAM(1033Mhz)的QuadCore Intel Xeon,它可以很好地,快速地运行前70k记录,在大约15分钟内完成。到那时,它已经达到了90k,大约需要25分钟,所以有些东西让它慢慢爬行。

我已经检查了Hibernate代码上的计时器,数据库检索的时间与往常一样。我甚至试图强制手动垃圾收集尝试这样做,但这也不起作用。

有问题的代码类似于:

val recordCount = repo.recordCount
val batchSize = 100
val batches = (0 to recordCount by batchSize).toList
val batchJobs = {
    for (batchStart <- batches) yield {
        future(new RecordFormatter().formatRecords(new Repo(sessionFactory.openSession),batchStart,batchSize)
    }
awaitAll(100000,batchJobs: *_)

在RecordFormatter内部(实际上没有命名,如果你不知道我的命名方案是否疯狂),它会对接下来的100条记录进行查询,然后再查询另一条查询以回退实际记录(在开始和之间使用结束值)然后将它们作为CSV写入文本文件。查看定时器输出,记录格式化程序中的每个操作大约需要5秒钟来撤回记录,然后需要0.1秒才能将其输出到文件。

尽管如此,一旦它减速,它只处理大约12批100每分钟的记录,而不是在该过程首次启动时每分钟有40批100条记录。

它会定期刷新Session并在每个RecordFormatter运行结束时关闭它(每个RecordFormatter都有自己的会话)。

我主要是在寻找Scala和期货的任何已知问题。我注意到,当它放慢速度时,它似乎没有使用所有八个可能的线程,这可以解释速度的下降,但对我来说这是一个谜,为什么它会突然停止并始终在75k记录标记附近。

谢谢!

编辑:更新的代码显示它使用yield和awaitAll,以防万一。

3 个答案:

答案 0 :(得分:3)

尝试绑定actor库将创建的最大线程数(期望由actor支持)。 actor线程非常重量级,在某些条件下,调度程序会创建它们,就像没有明天一样。这会占用大量的堆空间,并且会使您的程序花费大量时间执行垃圾回收。

这可以通过在命令行设置actors.maxPoolSize参数来完成......这类似于:-Dactors.maxPoolSize = 32或者你想要的最大线程数。

我还强烈建议您运行程序-Xprof以查看GC消耗的时间。

答案 1 :(得分:2)

它看起来像是一个内存问题。我会在内存使用方面获得转储,看看它的行为方式。如果gc时间增加太多,你就有罪魁祸首。然后,您可以增加JVM可用的内存以使其再次运行。

无论如何,请勿将batches转换为List。这是不必要的。如果您使用for / yield(在Scala 2.7上),则必须使用,但由于您没有产生任何内容,因此Range是更好的选择。

答案 2 :(得分:2)

与JDK捆绑在一起的jconsole应用程序(在$JAVA_HOME/bin/jconsole中)可用于在应用程序运行时附加到该应用程序。这非常适合告诉你一些事情:

  1. 该应用程序是否将所有时间花在GC上?
  2. 应用程序线程在做什么?
  3. 你能在这里公布结果吗?