Для простого распараллеливания, когда я отбрасываю кучу работы для обработки, а затем жду, пока все это вернется, я склонен использовать шаблон Futures.
class ActorExample {
import actors._
import Actor._
class Worker(val id: Int) extends Actor {
def busywork(i0: Int, i1: Int) = {
var sum,i = i0
while (i < i1) {
i += 1
sum += 42*i
}
sum
}
def act() { loop { react {
case (i0:Int,i1:Int) => sender ! busywork(i0,i1)
case None => exit()
}}}
}
val workforce = (1 to 4).map(i => new Worker(i)).toList
def parallelFourSums = {
workforce.foreach(_.start())
val futures = workforce.map(w => w !! ((w.id,1000000000)) );
val computed = futures.map(f => f() match {
case i:Int => i
case _ => throw new IllegalArgumentException("I wanted an int!")
})
workforce.foreach(_ ! None)
computed
}
def serialFourSums = {
val solo = workforce.head
workforce.map(w => solo.busywork(w.id,1000000000))
}
def timed(f: => List[Int]) = {
val t0 = System.nanoTime
val result = f
val t1 = System.nanoTime
(result, t1-t0)
}
def go {
val serial = timed( serialFourSums )
val parallel = timed( parallelFourSums )
println("Serial result: " + serial._1)
println("Parallel result:" + parallel._1)
printf("Serial took %.3f seconds\n",serial._2*1e-9)
printf("Parallel took %.3f seconds\n",parallel._2*1e-9)
}
}
По сути, идеясоздать коллекцию работников - по одному на рабочую нагрузку - и затем выбросить в них все данные с помощью !!который немедленно возвращает будущее.Когда вы пытаетесь прочитать будущее, отправитель блокируется до тех пор, пока работник фактически не завершит работу с данными.
Вы можете переписать вышеприведенное, чтобы вместо этого PriceCalculator
extended Actor
, а valueAll
координировали возвратданные.
Обратите внимание, что вы должны быть осторожны, передавая неизменяемые данные.
В любом случае, на машине, с которой я это печатаю, если вы запустите приведенное выше, вы получите:
scala> (new ActorExample).go
Serial result: List(-1629056553, -1629056636, -1629056761, -1629056928)
Parallel result:List(-1629056553, -1629056636, -1629056761, -1629056928)
Serial took 1.532 seconds
Parallel took 0.443 seconds
(Очевидно, у меня есть по крайней мере четыре ядра; параллельная синхронизация довольно немного варьируется в зависимости от того, какой работник получает какой процессор и что еще происходит на машине.)