Olá:
Estou experimentando usar Programação Paralela em Scala. Baseado neste exemplo do site StackOverflow, criei um programa baseado no Problema 1 do Project Euler. Experimentei três modos: O primeiro é uma execução simples, sem paralelismo. O segundo usando a API do java.util.concurrency, através de Executors e Callables. O Terceiro, baseado na sugestão da página do StackOverflow, usando scala.Futures. O objetivo é comparar os tempos de se percorrer o range paralelamente e executar a soma.
Segue-se o código:
package sandbox
import java.util.concurrent._
import scala.actors._
object TestPool {
def eval(n: Int): Boolean = (n % 3 == 0) || (n % 5 == 0)
def runSingle(max: Int): Int = (1 until max).filter(eval(_)).foldLeft(0)(_ + _)
def runPool(max: Int): Int = {
def getCallable(i: Int): Callable[Boolean] = new Callable[Boolean] { def call = eval(i) }
val pool = Executors.newFixedThreadPool(5)
val result = (1 until max).filter(i => pool.submit(getCallable(i)).get).foldLeft(0)(_ + _)
pool.shutdown
pool.awaitTermination(Math.MAX_LONG, TimeUnit.SECONDS)
result
}
def runFutures(max: Int): Int = (1 until max).filter(i => Futures.future(eval(i)).apply).foldLeft(0)(_ + _)
/**
* f é a função a ser executada. O retorno é uma Tuple2 contendo a soma e o
* tempo de execução.
*/
def test(max: Int, f: Int => Int): (Int, Long) = {
val t0 = System.currentTimeMillis
val result = f(max)
val deltaT = System.currentTimeMillis - t0
(result, deltaT)
}
def main(args : Array[String]) : Unit = {
val max = 10000
println("Single : " + test(max, runSingle))
println("Pool : " + test(max, runPool))
println("Futures: " + test(max, runFutures))
}
}
O resultados que obtive foram os seguntes:
- max = 10:
- max = 100:
- max = 1000:
- max = 10000:
Claramente usando as APis de concorrencia do Java e de Scala não está gerando os resultados esperados. Portanto eu pergunto: Onde estou errando? Qual seria a forma mais adequada de se utilizar a Concorrência? E quanto aos atores de Scala? Como eles poderiam ser utilizados?
Grato,