Why Scala for comprehension run Future functions sequentially?

人盡茶涼 提交于 2020-01-02 09:36:22

问题


Consider the following code:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration._

object FutureFor {
  def getA(n: Int) = {
    val x: Future[String] = Future {
      println("I'm getA")
      for (i <- 1 to 5) {
        println(".")
        Thread.sleep(200)
      }
      s"A$n"
    }
    x
  }

  def getB(n: Int) = {
    val x: Future[String] = Future {
      println("I'm getB")
      for (i <- 1 to 5) {
        println(".")
        Thread.sleep(200)
      }
      s"B$n"
    }
    x
  }

  def main(args: Array[String]) = {

    println("\nThis is sequential")
    val rs1 = for {
      a <- getA(1)
      b <- getB(1)
    } yield (a + b)
    println(Await.result(rs1, 1 minute))

    println("\nThis is concurrent")
    val first = getA(2)
    val second = getB(2)
    val rs2 = for {
      a <- first
      b <- second
    } yield (a + b)

    println(Await.result(rs2, 1 minute))
  }

}

The output of this code is:

This is sequential
I'm getA
.
.
.
.
.
I'm getB
.
.
.
.
.
A1B1

This is concurrent
I'm getB
.
I'm getA
.
.
.
.
.
.
.
.
.
A2B2

However I would think that in both the cases the Future should execute concurrently. What is it that is making the execution sequential in the first case?


回答1:


It executes sequentially because getB won't be called but only in the callback function of the Future returned by getA. It's explained very well here.

update: so the for comprehension translates to maps, flatMaps and filters, which on they turn are just turned into callbacks behind the scenes




回答2:


Can I just use source from Handling futures with for-comp, but if clauses are making things difficult to try to explain how I see the problem(cause I have those source already compiled)?

this for loop:

for {
  a <- fooService.getA()
  b <- fooService.getB()
} println(a + b)

just gets desugared by scalac using map and flatMap combinators so, lets rewrite it by hand:

fooService.getA.foreach{ a =>
  fooService.getB.foreach{ b =>
    println(a+b)
  }
}

This code seems sequential. If you would have yield keyword in for comprehension,

for {
  a <- fooService.getA()
  b <- fooService.getB()
} yield(a + b)

then it would be desugared to

fooService.getA.map{ a =>
  fooService.getB.flatMap{ b =>
    a + b
  }
}

Which is also sequential. for comprehension is no more no less than combination of map/flatMap/filter



来源:https://stackoverflow.com/questions/34379025/why-scala-for-comprehension-run-future-functions-sequentially

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!