简体   繁体   English

嵌套的 Future.sequence 顺序执行包含的 Futures

[英]Nested Future.sequence executes included Futures sequentially

I have a future( doFour ) that is executed and results passed to a flatmap.我有一个执行的未来( doFour )并将结果传递给平面图。 Inside the flatmap I execute two more future( doOne and doTwo ) functions expecting them to run on parallel but I see they are running sequentially (2.13).在平面图中,我执行了另外两个未来( doOnedoTwo )函数,期望它们并行运行,但我看到它们是按顺序运行的(2.13)。 Scastie斯卡斯蒂

Why are doOne and doTwo not execute in parallel?为什么doOnedoTwo不能并行执行?

How can I have them to run in parallel?我怎样才能让它们并行运行?

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future}

object Test {
  def doOne(): Future[Unit] = Future {
    println("startFirst");      Thread.sleep(3000);     println("stopFirst")
  }

  def doTwo(): Future[Unit] = Future {
    println("startSecond");      Thread.sleep(1000);      println("stopSecond")
  }


  def doFour(): Future[Unit] = Future {
    println("do 4");     Thread.sleep(1000);     println("done 4")

  }


  def main(args: Array[String]) {


    val resOut = doFour().flatMap { a =>

      val futureOperations = Seq(doOne(), doTwo())

      val res = Future.sequence(futureOperations)
      res
    }

    val stream = Await.result(resOut, Duration.Inf)
  }
}

A Future becomes eligible for execution as soon as it is created. Future一经创建就可以执行。 So this line creates two Futures that can potentially be executed:所以这一行创建了两个可能被执行的Futures

val futureOperations = Seq(doOne(), doTwo())

The call to Future.sequence will create a new Future that waits for each of the futures to complete in turn, but they will both already be available for execution by this point in the code.Future.sequence的调用将创建一个新的Future ,它等待每个 Future 依次完成,但它们都已经可以在代码中执行。

val res = Future.sequence(futureOperations)

If you want Future s to start sequentially you need to use map/flatMap :如果您希望Future s 按顺序启动,您需要使用map/flatMap

val res = doOne().map( _ => doTwo())

With this code doTwo will not be called until doOne completes (and not at all if doOne fails)使用此代码,在doTwo完成之前不会调用doOne (如果doOne失败,则根本不会调用)

The reason that this does not appear to happen in your example is that you are calling a blocking operation in your Future which is blocking a thread that would otherwise be used to execute other Future s.在您的示例中似乎没有发生这种情况的原因是您在Future中调用了一个阻塞操作,该操作阻塞了一个线程,否则该线程将用于执行其他Future s。 So although there are two Future s available for execution, only one is actually being executed at a time.因此,尽管有两个Future可用于执行,但实际上一次只执行一个。

If you mark the code as blocking it works correctly:如果您将代码标记为blocking ,则它可以正常工作:

import scala.concurrent.blocking

def doOne(): Future[Unit] = Future {
  blocking{println("startFirst");      Thread.sleep(3000);     println("stop First")}
}

def doTwo(): Future[Unit] = Future {
  blocking{println("startSecond");      Thread.sleep(1000);      println("stop Second")}
}

See the comments section for details of why the default behaviour is different on different versions, and why you should never make assumptions about the relative execution order of independent Future s.请参阅评论部分了解为什么不同版本的默认行为不同的详细信息,以及为什么您永远不应该对独立Future的相对执行顺序做出假设。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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