scala: параллельные коллекции не работают? - PullRequest
7 голосов
/ 03 июня 2011

Я пытаюсь использовать параллельные коллекции очень простым способом через .par - я ожидаю, что с коллекцией будут действовать не по порядку, но это не так:

scala> (1 to 10) map println
1
2
3
4
5
6
7
8
9
10

и

scala> (1 to 10).par map println
1
2
3
4
5
6
7
8
9
10

похоже, что в последнем случае порядок не должен быть последовательным. это со scala 2.9, у моей машины 2 ядра. это где-то неправильная конфигурация? спасибо!

edit: я действительно пробовал работать с большим набором (100k), и результат все еще был последовательным.

Ответы [ 2 ]

11 голосов
/ 03 июня 2011

YMMV:

scala> (1 to 10).par map println
1
6
2
3
4
7
5
8
9

Это тоже на двухъядерном процессоре ...

Я думаю, что если вы попробуете достаточно бегать, вы можете увидеть другие результаты. Вот фрагмент кода, который показывает, что происходит:

import collection.parallel._
import collection.parallel.immutable._

class ParRangeEx(range: Range) extends ParRange(range) {
  // Some minimal number of elements after which this collection 
  // should be handled sequentially by different processors.
  override def threshold(sz: Int, p:Int) = {
    val res = super.threshold(sz, p)
    printf("threshold(%d, %d) returned %d\n", sz, p, res)
    res
  }
  override def splitter = {
    new ParRangeIterator(range) 
        with SignalContextPassingIterator[ParRangeIterator] {
      override def split: Seq[ParRangeIterator] = {
        val res = super.split
        println("split " + res) // probably doesn't show further splits
        res
      }
    }
  }
}

new ParRangeEx((1 to 10)).par map println

В некоторых прогонах я получаю перемежающуюся обработку, в некоторых прогонах - последовательную обработку. Кажется, разделить нагрузку на две части. Если вы измените возвращенное пороговое число на 11, вы увидите, что рабочая нагрузка никогда не будет разделена.

Базовый механизм планирования основан на форк-объединении и краже работы. См. следующий исходный код JSR166 для некоторых идей. Вероятно, именно это определяет, будет ли один и тот же поток выполнять обе задачи (и, следовательно, кажется последовательным), или два потока работают над каждой задачей.

Вот пример выходных данных на моем компьютере:

threshold(10, 2) returned 1
split List(ParRangeIterator(over: Range(1, 2, 3, 4, 5)), 
  ParRangeIterator(over: Range(6, 7, 8, 9, 10)))
threshold(10, 2) returned 1
threshold(10, 2) returned 1
threshold(10, 2) returned 1
threshold(10, 2) returned 1
threshold(10, 2) returned 1
6
7
threshold(10, 2) returned 1
8
1
9
2
10
3
4
5
1 голос
/ 03 июня 2011

Ответ может очень хорошо выйти последовательно;Там просто нет гарантии для этого.На таком маленьком наборе вы обычно получаете его последовательно.Однако println вызывает системный вызов, если вы запустите его достаточно много раз, вы, вероятно, получите беспорядочную версию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...