【问题标题】:Why Scala for comprehension run Future functions sequentially?为什么用于理解的 Scala 按顺序运行 Future 函数?
【发布时间】:2016-03-26 13:03:55
【问题描述】:

考虑以下代码:

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))
  }

}

这段代码的输出是:

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

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

但是,我认为在这两种情况下,Future 都应该同时执行。在第一种情况下执行顺序的原因是什么?

【问题讨论】:

  • 这两种情况都是如此,所以为什么它不会阻止第二种情况。而且,Thread.sleepFuture 之内,所以任何其他Future 都不应该等待这个完成。这是我不明白的。

标签: scala concurrency future


【解决方案1】:

我可以只使用来自Handling futures with for-comp, but if clauses are making things difficult 的源吗? 尝试解释我是如何看待问题的(因为我已经编译了这些源代码)?

这个for循环:

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

只是被 scalac 使用 map 和 flatMap 组合器去糖,所以让我们手动重写它:

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

这段代码似乎是连续的。如果你有 yield 关键字用于理解,

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

那么它就会被脱糖

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

这也是顺序的。 for comprehension 不亚于 map/flatMap/filter 的组合

【讨论】:

    【解决方案2】:

    它是顺序执行的,因为getB不会被调用,而只会在getA返回的Future的回调函数中被调用。解释的很好here

    更新:所以for 理解转换为maps、flatMaps 和filters,而这只是turned into callbacks 在幕后

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-29
      • 2016-04-17
      • 1970-01-01
      • 1970-01-01
      • 2016-01-02
      • 1970-01-01
      • 2015-10-19
      • 2023-03-17
      相关资源
      最近更新 更多