奇怪的并行收集行为

时间:2011-08-21 16:23:02

标签: scala collections parallel-processing

我正在尝试使用scala并行集合来实现一些cpu密集型 任务,我想抽象出算法的执行方式 (顺序,并行或甚至分布),但代码不能像我一样工作 会怀疑,我不知道我做错了什么。

我想抽象出这个问题的方式如下:

// just measures time a block of code runs
def time(block: => Unit) : Long = {
  val start = System.currentTimeMillis
  block
  val stop = System.currentTimeMillis
  stop - start
}

// "lengthy" task
def work = {
  Thread.sleep(100)
  println("done")
  1
}

import scala.collection.GenSeq


abstract class ContextTransform {
  def apply[T](genSeq: GenSeq[T]): GenSeq[T]
}

object ParContextTransform extends ContextTransform {
  override def apply[T](genSeq: GenSeq[T]): GenSeq[T] = genSeq.par
}

// this works as expected
def callingParDirectly = {
  val range = (1 to 10).par

  // make sure we really got a ParSeq
  println(range) 
  for (i <- range) yield work
}

// this doesn't 
def callingParWithContextTransform(contextTransform: ContextTransform) = {
  val range = contextTransform(1 to 10)

  // make sure we really got a ParSeq
  println(range)
  for (i <- range) yield work
}

口译员的结果:

scala> time(callingParDirectly)
ParRange(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
done
// ...
done
res20: Long = 503

scala> time(callingParWithContextTransform(ParContextTransform))
ParRange(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
done
// ...
done
res21: Long = 1002

我的第一个赌注是该系列没有正确拆分和println的 “完成”确实表明......但如果我不屈服,上面的代码就能很好地运作 任何事情(只需运行工作方法)。

我无法理解为什么callingParWithContextTransform方法不起作用 像callingParDirectly;我错过了什么?

2 个答案:

答案 0 :(得分:8)

可能的罪魁祸首:SI-4843

答案 1 :(得分:6)

Daniel Sobral是对的,这是一个已知的错误。我可以使用Scala 2.9.1.RC3重现您的结果,但它已在主干中修复。这是一个演示减速的简化版本:

  // just measures time a block of code runs
  def time(block: => Unit) : Long = {
      val start = System.currentTimeMillis
      block
      val stop = System.currentTimeMillis
      stop - start
  }

  // "lengthy" task
  def work = {
      Thread.sleep(100)
      1
  }

  def run() {
    import scala.collection.GenSeq

    print("Iterating over ParRange: ")
    println(time(for (i <- (1 to 10).par) yield work))

    print("Iterating over GenSeq: ")
    println(time(for (i <- (1 to 10).par: GenSeq[Int]) yield work))
  }

  run()

我在2.9.1.RC3上获得的输出是

Iterating over ParRange: 202
Iterating over GenSeq: 1002

但是在2.10的每晚构建中,两个版本都在大约200ms内运行。