Multithreading flatMap一个期货列表的期货正在执行一个阻塞操作,那么为什么不将代码包含在阻塞{..}中呢?

Multithreading flatMap一个期货列表的期货正在执行一个阻塞操作,那么为什么不将代码包含在阻塞{..}中呢?,multithreading,scala,future,blocking,Multithreading,Scala,Future,Blocking,在学习上Coursera课程的一些练习和视频时,我看到了一个方法的定义,即“排序”未来的列表。该方法返回一个Future,它将在fts中等待所有期货(见下面的代码),并将这些结果打包到列表[T]中,当按顺序返回的Future[T]完成时,该列表将可用 def sequence[T](fts: List[Future[T]]): Future[List[T]] = { fts match { case Nil => Future(Nil) case (

在学习上Coursera课程的一些练习和视频时,我看到了一个方法的定义,即“排序”未来的
列表。该方法返回一个
Future
,它将在
fts
中等待所有期货(见下面的代码),并将这些结果打包到
列表[T]
中,当按顺序返回的
Future[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 可能永远不会运行

现在。。。我不明白的是为什么“match”表达式没有包装在“blocking”表达式中。难道我们不希望所有的平面映射都(潜在地)花费大量的时间吗

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

我也会把这个发到Coursera论坛,如果我得到回复,我也会发到这里

难道我们不希望所有的平面映射都(潜在地)花费大量的时间吗

没有
flatMap
只需构建一个新的
Future
并立即返回。它不会阻塞

看。以下是它的简化版本:

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.sequence
    返回的
    Future
    并不真正“起作用”。正如您在上面的代码中所看到的,您从
    flatMap
    获得的
    未来
    (因此,您从
    Future.sequence
    获得的
    未来
    )只是一个最终将由其他东西完成的承诺。唯一真正起作用的是
    ExecutionContext
    ;未来的
    s只是指定要做什么

    难道我们不希望所有的平面映射都(潜在地)花费大量的时间吗

    没有
    flatMap
    只需构建一个新的
    Future
    并立即返回。它不会阻塞

    看。以下是它的简化版本:

    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.sequence
    返回的
    Future
    并不真正“起作用”。正如您在上面的代码中所看到的,您从
    flatMap
    获得的
    未来
    (因此,您从
    Future.sequence
    获得的
    未来
    )只是一个最终将由其他东西完成的承诺。唯一真正起作用的是
    ExecutionContext
    ;未来的s只是指定要做什么