🎓 A1Learner
🔍
0 of 45 lessons completed

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?