覆盖scala中的默认并行集合行为

时间:2013-10-08 20:25:45

标签: multithreading performance scala parallel-processing

我有一个大型批量并行计算,我在scala中使用并行映射。我注意到,随着工人的完成,CPU使用量似乎逐渐下降。这一切都归结为对Map对象内部调用的调用

scala.collection.parallel.thresholdFromSize(length, tasksupport.parallelismLevel)

查看代码,我看到了:

def thresholdFromSize(sz: Int, parallelismLevel: Int) = {
  val p = parallelismLevel
  if (p > 1) 1 + sz / (8 * p)
  else sz
}

我的计算在大量核心上运行良好,现在我理解为什么......

thesholdFromSize(1000000,24) = 5209
thesholdFromSize(1000000,4) = 31251

如果我在24个CPU上有一个长度为1000000的数组,它将一直分为5209个元素。如果我将同一个数组传递到我的4 CPU机器上的并行集合中,它将停止在31251元素上进行分区。

应该注意,我的计算的运行时间并不统一。每单位运行时间可长达0.1秒。在31251项,即3100秒,或52分钟的时间,其他工人可以踩到并抓住工作,但事实并非如此。在并行计算期间监视CPU利用率时,我已经观察到了这种行为。显然我喜欢在大型机器上运行,但这并不总是可行的。

我的问题是:有没有办法影响并行集合,给它一个更小的阈值数,更适合我的问题?我唯一能想到的就是自己实现“Map”这个类,但这似乎是一个非常优雅的解决方案。

3 个答案:

答案 0 :(得分:0)

您想阅读Configuring Scala parallel collections。特别是,您可能需要实现TaskSupport特性。

答案 1 :(得分:0)

我认为你需要做的就是这样:

yourCollection.tasksupport = new ForkJoinTaskSupport(new scala.concurrent.forkjoin.ForkJoinPool(24))

parallelism参数默认为您拥有的CPU核心数,但您可以像上面一样覆盖它。这也显示在ParIterableLike的来源中。

答案 2 :(得分:0)

0.1秒足够大的时间来单独处理它。在单独的Runnable中处理每个单元(或10个单元)的处理,并将它们全部提交给FixedThreadPool。另一种方法是使用ForkJoinPool - 然后更容易控制所有计算的结束。