Странное поведение параллельной коллекции - PullRequest
7 голосов
/ 21 августа 2011

Я пытаюсь использовать параллельные коллекции scala для реализации некоторых ресурсоемких задач, я хотел абстрагироваться от способа выполнения алгоритма (последовательного, параллельного или даже распределенного), но код не работает какЯ подозреваю, и я понятия не имею, что я делаю неправильно.

Способ, которым я хотел абстрагироваться от этой проблемы, смоделирован ниже:

// 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's «done» действительно предполагает, что ... но приведенный выше код работает хорошо, если я ничего не даю (просто запустите метод работы).

Я не могу понять, почемуметод callingParWithContextTransform не работает как callingParDirectly;что мне не хватает?

Ответы [ 2 ]

8 голосов
/ 21 августа 2011

Возможный виновник: SI-4843 .

6 голосов
/ 21 августа 2011

Даниэль Собрал прав, это известная ошибка. Я могу воспроизвести ваши результаты с помощью 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 обе версии работают примерно за 200 мс.

...