// First import concurrent.Future import concurrent.ExecutionContext.Implicits.global for { _ <- Future { Thread.sleep(3000); println("a") } _ <- Future { Thread.sleep(2000); println("b") } _ <- Future { Thread.sleep(1000); println("c") } } {}
// Second
import concurrent.Future import concurrent.ExecutionContext.Implicits.global val future1 = Future { Thread.sleep(3000); println("a") } val future2 = Future { Thread.sleep(2000); println("b") } val future3 = Future { Thread.sleep(1000); println("c") } for { _ <- future1 _ <- future2 _ <- future3 } {}
You can use the command below to have a better understanding of what Scala compiler do under the hood:
$ scalac -Xprint:typer MainClass.scala
'First' will be desugared into:
scala.concurrent.Future.apply[Unit]({
java.lang.Thread.sleep(3000L); scala.Predef.println("a")
})(scala.concurrent.ExecutionContext.Implicits.global)
.foreach[Unit](((_: Unit) =>
scala.concurrent.Future.apply[Unit]({
java.lang.Thread.sleep(2000L); scala.Predef.println("b")
})(scala.concurrent.ExecutionContext.Implicits.global)
.foreach[Unit](((_: Unit) => scala.concurrent.Future.apply[Unit]({
java.lang.Thread.sleep(1000L); scala.Predef.println("c")
})(scala.concurrent.ExecutionContext.Implicits.global)
.foreach[Unit](((_: Unit) => ()))(scala.concurrent.ExecutionContext.Implicits.global)))(scala.concurrent.ExecutionContext.Implicits.global)))
(scala.concurrent.ExecutionContext.Implicits.global);
'Second' into
val future1: scala.concurrent.Future[Unit] = scala.concurrent.Future.apply[Unit]({
java.lang.Thread.sleep(3000L);
scala.Predef.println("a")
})(scala.concurrent.ExecutionContext.Implicits.global);
val future2: scala.concurrent.Future[Unit] = scala.concurrent.Future.apply[Unit]({
java.lang.Thread.sleep(2000L);
scala.Predef.println("b")
})(scala.concurrent.ExecutionContext.Implicits.global);
val future3: scala.concurrent.Future[Unit] = scala.concurrent.Future.apply[Unit]({
java.lang.Thread.sleep(1000L);
scala.Predef.println("c")
})(scala.concurrent.ExecutionContext.Implicits.global);
{
future1.flatMap[Unit](((_: Unit) => future2.flatMap[Unit](((_: Unit) => future3.map[Unit](((_: Unit) => ()))(scala.concurrent.ExecutionContext.Implicits.global)))(scala.concurrent.ExecutionContext.Implicits.global)))(scala.concurrent.ExecutionContext.Implicits.global);
()
}
In 'First' case the next Future will be created inside the '.foreach' of the first Future and so on.
In 'Second' case all 3 futures will be created first, executed in parallel and then flatMap'ped.
Since the for expression is desugared
to a series of nested flatMap
/ map
calls, the Future
instances in the first examples will run sequentially.
While the code in the second example will, depending on the ExecutionContext
in scope, run the Future
instances in parallel.
Another thing to keep in mind is that scala Futures are strict, which means that you can't separate Future
definition from its execution. You can read about this and other Future
weaknesses here:
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.