I have written this code and it works
import scala.concurrent.{Future}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success, Random}
object TestFuture2 {
def bigCalc() : Future[Int] = Future {
Thread.sleep(1000)
40
}
}
object Main2 extends App {
val x = TestFuture2.bigCalc
val y = TestFuture2.bigCalc
val z = TestFuture2.bigCalc
val v = for {
r1 <- x
r2 <- y
r3 <- z
} yield (r1 + r2 + r3)
v onSuccess {
case x1 => println(x1)
}
System.in.read()
}
So when I run this, I get 120. Good.
but I don't like that I am summing the values in a for loop
for {
r1 <- x
r2 <- y
r3 <- z
} yield (r1 + r2 + r3)
What if I called my functions like
val x = List(TestFuture2.bigCalc, TestFuture2.bigCalc, TestFuture2.bigCalc, TestFuture2.bigCalc, TestFuture2.bigCalc)
now how will I sum?
I tried
x.reduce(_ + _)
but that doesn't work.
scala> x.reduce(_ + _)
<console>:17: error: type mismatch;
found : scala.concurrent.Future[Int]
required: String
x.reduce(_ + _)
Future.sequence
transforms a Traversable[Future[T]]
into a Future[Traversable[T]]
(this future will be failed, if any of the futures in the original list failed). After that you can simply call sum
on the content of this Future:
Future.sequence(x).map(_.sum)
TL;DR Use: Future.reduce(futures)(_ + _)
The main issue with your sample of code is the confusion between Traversable#reduce
and Future#reduce
. You want to use the second but you use the first.
The Traversable#reduce
needs a reduction function that has this signature: Tuple2[Future[Int], Future[Int]] => Future[Int]
.
The Future#reduce
on the other hand will automatically unpack the values stored in the futures for you. It needs a reduction function with this signature: Tuple2[Int, Int] => Int
. A lot more practical.
An example using the Traversable#reduce
function:
val futures = List(TestFuture2.bigCalc, TestFuture2.bigCalc, TestFuture2.bigCalc, TestFuture2.bigCalc, TestFuture2.bigCalc)
val reduced = futures.reduce((first: Future[Int], second: Future[Int]) => first.flatMap(firstResult => second.map(secondResult => secondResult + firstResult)))
An example using the Future#reduce
function:
val futures = List(TestFuture2.bigCalc, TestFuture2.bigCalc, TestFuture2.bigCalc, TestFuture2.bigCalc, TestFuture2.bigCalc)
val reduced = Future.reduce(futures)((first: Int, second: Int) => first + second)
You can directly use Future#sequence
instead, as this is what Future#reduce
uses it under the hood. But why would you use the latter then? It returns a future failure if your list is empty. So usage of one or the other depends on your requirements. If the list should never be empty, use Future#reduce
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With