0

For example you can do:

Future(/* A */).flatMap(_ => Future(/* B */).flatMap(_ => Future(/* C */)))

Here B depends on A to complete, is there a clean way to compose the futures so that C depends on both A and B to complete and A and B can run in parallel?

3 Answers3

2

I think what you are looking for is Future.sequence method that allows you reduce a sequence of Futures into a single Future. Here is a simple example:

def createFuture(name: String, sleep: Int): Future[(String, Int)] = {
  Future({
    println(s"Starting $name with sleep $sleep")
    Thread.sleep(sleep)
    println(s"After $name")
    (name, sleep)
  })
}

val rnd = new Random()
val fa = createFuture("A", rnd.nextInt(1000) + 500)
val fb = createFuture("B", rnd.nextInt(1000) + 500)
val ff = Future.sequence(List(fa, fb)).flatMap(l => createFuture("C" + l.map(_._2).sum, 100))
Await.result(ff, Duration.Inf)

Output for one of runs is:

Starting B with sleep 1287
Starting A with sleep 550
After A
After B
Starting C1837 with sleep 100
After C1837

If you also want to have "fast failure", you may consider a more complicated answers from How to wait for several Futures

SergGr
  • 23,570
  • 2
  • 30
  • 51
0

for yield is clean way to do this and it's equal to flatMap, like:

val futureA = Future {
  // do something
}
val futureB = Future {
  // do something
}
for {
_ <- futureA
_ <- futureB
} yield Future {
  /* C */
}

Initial futureA and futureB before for comprehensive, they will run in parallel.

chengpohi
  • 14,064
  • 1
  • 24
  • 42
  • I need A and B to run in parallel though, this will run them sequentially – goodOldFashioned May 25 '17 at 18:20
  • 1
    @goodOldFashioned This will only run them sequentially if you start them in the `for` comprehension. If `futureA` and `futureB` are something like `Future[_]` and not `() => Future[_]` then this will work fine – Tyler May 25 '17 at 19:33
0

Future(A).zipWith(Future(B))((_,_) => C)

Viktor Klang
  • 26,479
  • 7
  • 51
  • 68