简体   繁体   中英

Chaining Futures in Scala

Consider this:

val f1 = Future {}

val f2 = Future {}

f1.flatMap(_ => f2)

In this case, is it possible that f2 completes before f1 completes ?

I suspect yes.

So how could I fix that ? I mean, how can I make sure that f2 starts only after f1 has completed ?

Would this work/(be good style):

def f1 = Future {}

def f2 = Future {}

f1.flatMap(_ => f2)

?

As soon as you define a Future {} it is started right away, which means when you define f1 and f2 as two futures f1 starts executing and then f2 starts right way.

So any of those can finish first.

See REPL example below when you define Future as val it is executed right away.

scala> import scala.concurrent.Future
import scala.concurrent.Future

scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global

scala> val f1 = Future { Thread.sleep(5000); println("f1 finished")}
f1: scala.concurrent.Future[Unit] = Future(<not completed>)

scala> val f2 = Future { println("f2 finished")}
f2 finished
f2: scala.concurrent.Future[Unit] = Future(<not completed>)

scala> f1 finished

you can use for comprehension to make sure f1 starts first, . for comprehension itself is expanded to flatMap

scala> for { f1 <- Future { Thread.sleep(5000); println("f1 started"); 100}
     |       f2 <- Future { println("f2 started"); 200 }
     | } yield (f1, f2)
res1: scala.concurrent.Future[(Int, Int)] = Future(<not completed>)

scala> f1 started
f2 started

Or even within your example, you can use inline Futures instead of evaluated variables.

scala> Future { Thread.sleep(5000); println("f1 finished")}.flatMap {f => Future {println("f2 started"); 200}} 
res2: scala.concurrent.Future[Int] = Future(<not completed>)

scala> f1 finished
f2 started

And the best way is to use functions,

scala> def f1 = Future { Thread.sleep(5000); println("f1 finished")}
f1: scala.concurrent.Future[Unit]

scala> def f2 = Future {println("f2 started"); 200}
f2: scala.concurrent.Future[Int]

scala> f1.flatMap(_ => f2)
res3: scala.concurrent.Future[Int] = Future(<not completed>)

scala> f1 finished
f2 started

Replace val with def, basically instant compute to lazy compute.

def f1 = Future {}
def f2 = Future {}

f1.flatMap(_ => f2)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM