首页 文章

flatMap期货列表的期货正在进行阻止操作,那么为什么不将代码括在阻塞{...}中呢?

提问于
浏览
1

通过Reactive Programming上的Coursera课程中的一些练习和视频,我看到了一种方法的定义,以期待未来的方法 . 该方法返回 Future ,它将在 fts (见下面的代码)中等待所有期货的工作,并将这些结果打包成 List[T] ,当序列返回的 Future[List[T]] 完成时,这些结果将可用 .

def sequence[T](fts: List[Future[T]]): Future[List[T]] = {
    fts match {
        case Nil => Future(Nil)
        case (ft::fts) => ft.flatMap(t => sequence(fts)
            .flatMap(ts => Future(t::ts)))
    }
}

这段代码是由教师给出的,所以我猜它应该代表如何做这种事情的最佳模式 . 然而,在讲座的其他地方,教师们说:

每当您有长时间运行的计算或阻塞时,请确保在阻塞构造内部运行它 . 例如:blocking {
了Thread.sleep(1000)
}
用于将一段代码指定为可能阻塞的代码 . 具有阻塞构造的异步计算通常在单独的线程中调度,以避免潜在的死锁 . 示例:假设您有一个等待计时器或资源或监视条件的未来f,这些条件只能由其他未来g来实现 . 在这种情况下,执行等待的f中的代码部分应该包含在阻塞中,否则将来可能永远不会运行g .

现在......我不明白为什么“匹配”表达式没有包含在“阻塞”表达式中 . 难道我们不希望所有flatMapping(可能)花费大量时间吗?

附注:scala.concurrent.Future类中有一个“官方”序列方法,该实现也不使用阻塞 .

我也会将它发布到Coursera论坛,如果我得到回复,我也会在这里发布 .

1 回答

  • 4

    难道我们不希望所有flatMapping(可能)花费大量时间吗?

    不 . flatMap 只是构造一个新的 Future 并立即返回 . 它不会阻止 .

    the default implementation of flatMap . 这是它的简化版本:

    trait Future[+T] {
    
      def flatMap[S](f: T => Future[S])
                    (implicit executor: ExecutionContext): Future[S] = {
    
        val promise = new Promise[S]()
    
        this.onComplete {
    
          // The first Future (this) failed
          case Failure(t) => promise.failure(t)
    
          case Success(v1) =>
    
            // Apply the flatMap function (f) to the first Future's result
            Try(f(v1)) match {
    
              // The flatMap function (f) threw an exception
              case Failure(t) => promise.failure(t)
    
              case Success(future2) =>
                future2.onComplete {
    
                  // The second Future failed
                  case Failure(t) => promise.failure(t)
    
                  // Both futures succeeded - Complete the promise
                  // successfully with the second Future's result.
                  case Success(v2) => promise.success(v2)
                }
            }
        }
        promise.future
      }
    }
    

    调用 flatMap 时会发生什么情况:

    • 创建承诺

    • 为此未来添加回调

    • 回报承诺

    该方法返回一个Future,它将完成等待所有期货的工作

    我认为这种描述有点误导 . 你从 Future.sequence 回来的 Future 并不是真的"do work" . 正如你在上面的代码中看到的那样,你从 flatMap 得到的 Future (以及你从 Future.sequence 获得的 Future )只是一个最终将由其他东西完成的承诺 . 唯一真正做到的是 ExecutionContext ; Future 只是指定要做什么 .

相关问题