Parallel Patterns
A parallel pattern is a way to split work into independent parts that run at the same time. The parts are then combined into one final result.
Two halves run as two futures
The first half sums to 6 and the second half sums to 15. Their total is printed.
import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.*
@main def main(): Unit =
val left = Future((1 to 3).sum)
val right = Future((4 to 6).sum)
val total = for
a <- left
b <- right
yield a + b
println(Await.result(total, 5.seconds))Chunks are summed in order
The numbers 1 to 12 are split into chunks of four. Each chunk sum is collected in order.
import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.*
@main def main(): Unit =
val chunks = List.range(1, 13).grouped(4).toList
val parts = chunks.map(chunk => Future(chunk.sum))
println(Await.result(Future.sequence(parts), 5.seconds))Mapping then reducing gives one total
Each number is doubled first. The doubled values are then summed to one total.
import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.*
@main def main(): Unit =
val parts = List(1, 2, 3, 4).map(n => Future(n * 2))
val total = Future.sequence(parts).map(values => values.sum)
println(Await.result(total, 5.seconds))Example
import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.*
@main def main(): Unit =
val chunks = List.range(1, 21).grouped(5).toList
val parts = chunks.map(chunk => Future(chunk.sum))
val total = Future.sequence(parts).map(values => values.sum)
println(Await.result(total, 5.seconds))Key points
- Independent: Independent parts do not depend on each other, so they can run at the same time.
- Split: Splitting breaks one large list into smaller chunks.
- Use Future.sequence to wait for every part and keep the part results in order.
- Combine: Combining adds the part results into one total.
- Map-reduce: Map-reduce is the shape where each part is first mapped to a partial result and then all partial results are reduced to one value.
In this example, the numbers 1 to 20 are split into four chunks of five. Each chunk is summed in its own future, sequence collects the four partial sums, and map adds them to 210.
Note
Parallel collections live in a separate library, so this lesson builds the same shape with futures from the standard library.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Scastie
Exercise
Why split work into independent parts?