当前位置: 首页 > 知识库问答 >
问题:

Scala等待未来的序列

东门子昂
2023-03-14

我希望像下面这样的代码可以等待这两种未来,但是没有。

object Fiddle {
  val f1 = Future {
    throw new Throwable("baaa") // emulating a future that bumped into an exception
  }

  val f2 = Future {
    Thread.sleep(3000L) // emulating a future that takes a bit longer to complete
    2
  }

  val lf = List(f1, f2) // in the general case, this would be a dynamically sized list

  val seq = Future.sequence(lf) 

  seq.onComplete {
    _ => lf.foreach(f => println(f.isCompleted))
  }
}

val a = FuturesSequence

我以为< code>seq.onComplete会在完成自身之前等待它们全部完成,但事实并非如此;它会导致:

true
false

在scala.concurrent.Future的源代码中有点难以遵循,我想知道如何实现等待(动态大小的)序列的所有原始未来的并行,或者这里可能有什么问题。

编辑:相关问题:https://worldbuilding.stackexchange.com/questions/12348/how-do-you-prove-youre-from-the-future:)

共有3个答案

竺翰海
2023-03-14

这是一个支持前面答案的示例。有一种简单的方法可以做到这一点,只需使用标准的Scala API。

在这个例子中,我正在创建3个期货。这些操作将分别在 5 秒、7 秒和 9 秒完成。对 Await.result调用将被阻止,直到所有期货都得到解决。一旦所有3个期货完成,a将被设置为List(5,7,9),执行将继续。

此外,如果在任何期货中引发异常,等待。结果将立即取消阻止并引发异常。取消注释<code>异常(…)

  try {
    val a = Await.result(Future.sequence(Seq(
      Future({
        blocking {
          Thread.sleep(5000)
        }
        System.err.println("A")
        5
      }),
      Future({
        blocking {
          Thread.sleep(7000)
        }
        System.err.println("B")
        7
        //throw new Exception("Ha!")
      }),
      Future({
        blocking {
          Thread.sleep(9000)
        }
        System.err.println("C")
        9
      }))),
      Duration("100 sec"))

    System.err.println(a)
  } catch {
    case e: Exception ⇒
      e.printStackTrace()
  }
韦阳晖
2023-03-14

由< code>Future.sequence生成的< code>Future在以下任一情况下完成:

  • 所有期货均已成功完成,或
  • 其中一个期货失败了

第二点是在您的案例中发生的情况,在包装的未来中的一个失败后立即完成是有意义的,因为在失败的案例中,包装的未来只能保存一个可丢弃的。等待其他期货是没有意义的,因为结果将是同样的失败。

高峻
2023-03-14

等待所有结果(失败与否)的一种常见方法是在未来将失败“提升”到一个新的表示中,这样所有的未来都会以某种结果完成(尽管它们可能以表示失败的结果完成)。一种自然的方法是提升到<code>尝试<code>。

Twitter的 futures 实现提供了一个 liftToTry 方法,使这变得微不足道,但你可以用标准库的实现做类似的事情:

import scala.util.{ Failure, Success, Try }

val lifted: List[Future[Try[Int]]] = List(f1, f2).map(
  _.map(Success(_)).recover { case t => Failure(t) }
)

现在,Future.sequence(lifted)将在每个未来完成时完成,并将使用Try表示成功和失败。

因此,等待一系列期货的所有原始期货的通用解决方案可能如下所示,假设执行上下文当然是隐式可用的。

  import scala.util.{ Failure, Success, Try }

  private def lift[T](futures: Seq[Future[T]]) = 
    futures.map(_.map { Success(_) }.recover { case t => Failure(t) })

  def waitAll[T](futures: Seq[Future[T]]) =
    Future.sequence(lift(futures)) // having neutralized exception completions through the lifting, .sequence can now be used

  waitAll(SeqOfFutures).map { 
    // do whatever with the completed futures
  }
 类似资料:
  • 我有一个方法,可以返回期货的 现在我想等待,直到所有的future都成功完成处理,或者future返回其输出的任何任务抛出异常。即使一项任务引发异常,等待另一项任务也没有意义。 简单的方法是 但这里的问题是,例如,如果第四个期货抛出异常,那么我将不必要地等待前三个期货可用。 如何解决这个问题?会以任何方式倒数闩锁帮助吗?我无法使用Future,因为java文档说

  • 我想运行相同类型的任务(工作线程),但一次不超过一定数量的任务。当任务完成时,其结果是新任务的输入,然后可以启动该任务。 有没有好的方法可以在C 11中使用异步/未来范式来实现这一点? 乍一看,它看起来很简单,你只是生成多个任务: 然后,运行以获取任务的异步结果。 然而,这里的问题是,未来的对象必须存储在某种队列中并一个接一个地等待。但是,可以一遍又一遍地迭代未来的对象,检查它们中的任何一个是否准

  • 问题内容: 我有一种返回List期货的方法 现在,我要等待,直到所有期货都成功完成处理,或者所有由期货返回输出的任务都引发异常。即使一项任务引发异常,也没有必要等待其他期货。 简单的方法是 但是这里的问题是,例如,如果第4个期货抛出异常,那么我将不必要地等待前3个期货可用。 如何解决呢?会以任何方式倒计时闩锁帮助吗?我无法使用Future,isDone因为Java文档说 问题答案: 你可以使用Co

  • 我正在尝试执行一些相互引用作为外键的查询,因此我必须等到外部未来完成。此算法放置在返回未来的函数中。 运行它时,我得到了这个: === TO CLIENT === 已完成存档 已完成全部 === TO CLIENT === 失败的 单词已完成 的单词 已完成 标记在博客中 完成投票 所以我的问题是,我怎么能等到未来的< code>mysql完成它的“childs”(在< code>whenComp

  • 我想利用Tokio的运行时来处理可变数量的异步期货。由于在编译时期货的计数是未知的,因此 FuturesUnorderd 似乎是我的最佳选择(像 这样的宏需要在编译时指定你的分支;join_all可能是可能的,但是当顺序无关紧要时,文档建议“在很多情况下”FuturesUnordered)。 这个片段的逻辑是一个recv()循环,它被推送到期货桶中,应该一直运行。当新数据到达时,它的解析/处理也被

  • 是否有一种方法可以在不阻塞事件循环的情况下等待一个未来完成? 我知道这个错误通常意味着什么,但我不知道在这种情况下...我试图在谷歌上搜索它,但没有找到任何关于将哪份清单放在哪里的明确解释。和以前一样,除非是强制性的,我更喜欢一次学一件事。 那么,回到这个问题:“基本”Vert.x是否有一种方法可以在事件循环不受干扰的情况下等待未来?