amorfis amorfis - 1 month ago 9
Scala Question

How to run Scalaz Tasks in parallel

I have a bunch of Scalaz Tasks. Created like this:

val tasks = for (i <- 1 to 50) yield {
Task.delay({
Thread.sleep(100L)
println(i)
i
})
}

val r = Nondeterminism[Task].gatherUnordered(tasks).run
println(r.mkString(" "))


I would expect the tasks to run in parallel. To print numbers in random order, and not to take 5 seconds (there are 50 tasks and 100 millis sleep in each).

However, it is clear that each task takes 100 millis, all of them take 5 seconds, and the created list is ordered.

How to run them in parallel? Where does Task take the thread to run on?

Answer

Task.delay suspends evaluation of its argument, but it doesn't say anything about where the evaluation will happen. You want Task.apply, which has the same signature except that it takes an implicit ExecutorService that will decide which thread the evaluation will happen in:

import scalaz.Nondeterminism, scalaz.concurrent.Task

val tasks = for (i <- 1 to 50) yield {
  Task {
    Thread.sleep(100L)
    println(i)
    i
  }
}

val r = Nondeterminism[Task].gatherUnordered(tasks).run
println(r.mkString(" "))

This will use the default ExecutorService, which wraps a fixed thread pool. If you want a different strategy, you can either put a different ExecutorService into implicit scope, or provide one explicitly in a second argument list for Task.apply.