【问题标题】:Do all futures need to be waited on to guarantee their execution?是否需要等待所有期货以保证其执行?
【发布时间】:2017-01-27 16:20:47
【问题描述】:

我们有一个 Scala Play 网络应用程序,它执行一些数据库操作作为 HTTP 请求的一部分,每个操作都是一个 Future。通常我们将 Futures 冒泡到一个异步控制器动作中,并让 Play 处理等待它们。

但我也注意到,在许多地方,我们并没有冒泡 Future,甚至没有等待它完成。我认为这很糟糕,因为这意味着如果未来失败,HTTP 请求不会失败,但它是否真的保证未来将被执行,因为没有任何东西会等待它的结果?在服务 HTTP 请求后,Play 会丢弃未等待的期货,还是让它们在后台运行?

【问题讨论】:

    标签: scala playframework


    【解决方案1】:

    TL;DR

    1. 在发送 HTTP 响应后,Play 不会杀死您的 Futures。
    2. 如果您的任何Futures 失败,则不会报告错误。

    加长版

    发送 HTTP 响应后,您的 futures 不会被终止。您可以像这样自己尝试一下:

      def futuresTest = Action.async { request =>
    
        println(s"Entered futuresTest at ${LocalDateTime.now}")
    
        val ignoredFuture = Future{
          var i = 0
          while (i < 10) {
            Thread.sleep(1000)
            println(LocalDateTime.now)
            i += 1
          }
        }
    
        println(s"Leaving futuresTest at ${LocalDateTime.now}")
    
        Future.successful(Ok)
      }
    

    但是,如果任何期货失败,请求不会失败,这是对的。如果这是一个问题,那么您可以使用 for comprehensionflatMaps 来构建未来。这是您可以做什么的示例(我假设您的 Futures 仅执行副作用 (Future[Unit])

    让你的期货并行执行

    val dbFut1 = dbCall1(...)
    val dbFut2 = dbCall2(...)
    val wsFut1 = wsCall1(...)
    val fut = for(
        _ <- dbFut1;
        _ <- dbFut2;
        _ <- wsFut1
    ) yield ()
    
    fut.map(_ => Ok)
    

    让它们按顺序执行

    val fut = for(
        _ <- dbCall1(...);
        _ <- dbCall2(...);
        _ <- wsCall2(...)
    ) yield ()
    
    fut.map(_ => Ok)
    

    【讨论】:

      【解决方案2】:

      它是否真的能保证未来会被执行, 既然没有什么会等待它的结果吗?会玩掉 服务 HTTP 请求后未等待的期货,或离开 他们在后台运行?

      这个问题实际上比 Play 更深入。您通常会问“如果我不同步等待未来,我怎么能保证它实际上会在没有被 GC 的情况下完成?”。要回答这个问题,我们需要了解 GC 实际如何查看线程。从 GC 的角度来看,线程就是我们所说的“根”。这样的根是堆遍历其对象并查看哪些对象适合收集的起点。例如,根中还有静态字段,已知它们在应用程序的整个生命周期中都存在。

      所以,当你这样看待它时,想想Future 的实际作用,它是将一个在专用线程上运行的函数排队,该函数来自通过底层ExecutorService 可用的线程池(我们指就像 Scala 中的 ExecutionContext 一样),您会看到即使您没有等待完成,JVM 运行时确实保证您的 Future 将运行完成。至于包装函数的 Future 对象,它持有对未完成函数体的引用,因此 Future 本身不会被收集。

      从这个角度考虑,这完全合乎逻辑,因为Future 的执行是异步发生的,我们通常使用诸如mapflatMap 等延续以异步方式继续处理它, onComplete

      【讨论】:

        猜你喜欢
        • 2014-02-04
        • 1970-01-01
        • 2018-03-24
        • 2020-10-31
        • 1970-01-01
        • 2016-03-07
        • 1970-01-01
        • 2015-06-03
        • 1970-01-01
        相关资源
        最近更新 更多