Вы можете использовать Scala Parallel Collections.В настоящее время они являются частью ночных выпусков Scala и будут выпущены в Scala 2.9.Идея состоит в том, что большинство операций, доступных в обычных коллекциях, распараллеливаются, поэтому параллельные коллекции могут использоваться одинаково.
В настоящее время доступно несколько типов коллекций - параллельные диапазоны, параллельные массивы и параллельные хэши.,Например, вы можете вызывать параллельные операции map
и fold
для параллельного массива следующим образом:
scala> val pa = (0 until 10000).toArray.par
pa: scala.collection.parallel.mutable.ParArray[Int] = ParArray(0, 1, 2, 3, 4, 5, 6,...
scala> pa.map(_ + 1)
res0: scala.collection.parallel.mutable.ParArray[Int] = ParArray(1, 2, 3, 4, 5, 6, 7,...
scala> pa map { v => if (v % 2 == 0) v else -v }
res1: scala.collection.parallel.mutable.ParArray[Int] = ParArray(0, -1, 2, -3, 4, -5,...
scala> pa.fold(0) { _ + _ }
res2: Int = 49995000
Также доступны другие операции параллельного сбора.Обратите внимание, что fold
должен принимать ассоциативный оператор - в приведенном выше примере сложение является ассоциативным ((A + B) + C == A + (B + C)), т.е. вы можете добавлять подпоследовательности чисел в любом порядке, и вывсегда получит одинаковую сумму (reduce
имеет аналогичный контракт).
Еще одна вещь, о которой следует помнить, это то, что замыкания, передаваемые в параллельные коллекции, вызываются одновременно.Если они имеют побочные эффекты, такие как изменение локальной переменной в среде, эти обращения должны быть синхронизированы.Например, вы можете сделать что-то вроде этого:
scala> var a = 0
a: Int = 0
scala> pa foreach { a += _ }
scala> a
res1: Int = 49995000
scala> a = 0
a: Int = 0
scala> pa foreach { a += _ }
scala> a
res7: Int = 49990086
и каждый раз получать разные результаты, потому что foreach
вызывает { a += _ }
параллельно.В приведенном выше примере a
должен быть синхронизирован, защищен блокировкой или атомарностью.
Но идея состоит в том, чтобы использовать встроенные комбинаторы для выполнения задачи и ориентироваться на функциональное программирование, избегая локальныхэффекты, как в примере выше.
Возможно, вы захотите немного больше прочитать об их внутренних механизмах в ссылках, приведенных в другом ответе.