2

Let's say I have a function func1 that needs to return a Future with two integers. Each of the two values are returned by independent futures, like so:

def f1 = Future { 1 } def f2 = Future { 2 } def func1 : Future[(Int,Int)] = { val future1 = f1 future1.map { result1 => result1 * 10 } val future2 = f2 future2.map { result2 => result2 * 20 } } 

I need future1 wait until future2 ends (or vice versa) to return both results as (Int,Int). How can this be accomplished?

3 Answers 3

4

That's precisely what the zip method on futures does:

val futurePair: Future[(Int, Int)] = future1.zip(future2) 

Note that if you haven't instantiated your futures before (say, if future1 and future2 are defs, not vals), this will run the two computations in parallel, while a for comprehension (or flatMap) would wait for the first one to succeed before starting the second one.

Sign up to request clarification or add additional context in comments.

3 Comments

What happens if there are 3 or 4 futures? Is it possible to have a Tuple4? Or will it be nested tuples?
It will be nested tuples. But you can always use map to give them the form you desire. If you have a List[Future[Int]], you can even use the static method Future.sequence to wait for all of them into a Future[List[Int]].
To explain what I mean about using map, you can do future1 zip future2 zip future3 map { case ((a, b), c) => (a, b, c) }
1

A for-comprehension is the best option here:

scala> import scala.concurrent.Future import scala.concurrent.Future scala> import concurrent.ExecutionContext.Implicits.global import concurrent.ExecutionContext.Implicits.global scala> def f1 = Future{1} f1: scala.concurrent.Future[Int] scala> def f2 = Future{2} f2: scala.concurrent.Future[Int] scala> for {result1 <- f1; result2 <- f2} yield (result1 * 10, result2 * 20) res0: scala.concurrent.Future[(Int, Int)] = scala.concurrent.impl.Promise$DefaultPromise@71f67a79 

More information can be found here and here.

Note: this will run the two Futures in sequence while Cyrille Corpet's solution will run them in parallel.

1 Comment

This runs the f1 and f2 in sequence. The other answer is better.
1

You can use a for-comprehension for futures that have already started like this:

val f1: Future[Int] = ??? val f2: Future[Int] = ??? val f3: Future[Int] = ??? val futureInts: Future[(Int, Int, Int)] = for { result1 <- f1 result2 <- f2 result3 <- f3 } yield (result1, result2, result3) 

If the futures were assigned to lazy vals or defs then this wouldn't work, because the futures would not have been started (if you start the futures inside the for comprehension, then they will be executed sequentially). Here is an example of starting them, and then waiting for them with for.

Example:

val f1: Future[Int] = Future { println("starting f1") Thread.sleep(1000) 1 } val f2: Future[Int] = Future { println("starting f2") Thread.sleep(3000) 2 } val f3: Future[Int] = Future { println("starting f3") Thread.sleep(2000) 3 } val futureInts: Future[(Int, Int, Int)] = for { result1 <- f1 result2 <- f2 result3 <- f3 } yield (result1, result2, result3) futureInts.map { case tuple => println(tuple) } 

Output:

starting f1 // These first starting f3 // threes statements starting f2 // happen right away. (1,2,2) // Then this prints a three seconds later 

In your case you could do this:

def func1 : Future[(Int,Int)] = { // Start futures val future1 = f1.map(_ * 10) val future2 = f2.map(_ * 20) // Wait for both futures, and return a tuple for { result1 <- future1 result2 <- future2 } yield (result1, result2) } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.