как избежать условий гонки с параллельными коллекциями scala - PullRequest
6 голосов
/ 31 марта 2012

Предназначены ли параллельные коллекции для выполнения операций с побочными эффектами? Если так, как вы можете избежать условий гонки? Например:

var sum=0
(1 to 10000).foreach(n=>sum+=n); println(sum)

50005000

нет проблем с этим. Но если попытаться распараллелить, условия гонки произойдут:

var sum=0
(1 to 10000).par.foreach(n=>sum+=n);println(sum)

49980037

Ответы [ 2 ]

17 голосов
/ 31 марта 2012

Быстрый ответ: не делай этого.Параллельный код должен быть параллельным , а не параллельным.

Лучший ответ:

val sum = (1 to 10000).par.reduce(_+_) // depends on commutativity and associativity

См. Также aggregate.

4 голосов
/ 31 марта 2012

Параллельный регистр не работает, потому что вы не используете изменчивые переменные, следовательно, не гарантируете видимость ваших записей и потому что у вас есть несколько потоков, которые делают следующее:

  1. читать sum в регистр
  2. добавить в регистр со значением sum
  3. записать обновленное значение обратно в память

Если 2 потока выполнят шаг 1 сначала один за другим, а затем перейдут к выполнению остальных шагов, описанных выше, в любом порядке, они перезапишут одно из обновлений.

  1. Используйте аннотацию @volatile, чтобы обеспечить видимость sum при выполнении чего-либо подобного. См. здесь .
  2. Даже с @volatile из-за неатомарности приращения вы потеряете некоторые приращения. Вы должны использовать AtomicInteger s и их incrementAndGet.
  3. Хотя использование атомарных счетчиков гарантирует правильность, наличие общих переменных сильно снижает производительность - ваша общая переменная теперь является узким местом производительности, потому что каждый поток будет пытаться атомарно записать в одну и ту же строку кэша. Если вы пишете в эту переменную нечасто, это не будет проблемой, но, поскольку вы делаете это на каждой итерации, здесь не будет никакого ускорения - фактически, из-за передачи владения строкой кэша между процессорами, это, вероятно, будет медленнее .

Итак, как предложил Даниил, используйте для этого reduce.

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