我希望像下面这样的代码会等待两个期货,但事实并非如此 .
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
我假设 seq.onComplete
会在完成之前等待他们全部完成,但不是这样;它导致:
true
false
.sequence
在scala.concurrent.Future的源代码中有点难以理解,我想知道如何实现一个等待(动态大小)序列的所有原始未来的并行,或者这里可能存在的问题 .
编辑:一个相关的问题:https://worldbuilding.stackexchange.com/questions/12348/how-do-you-prove-youre-from-the-future :)
4 回答
等待所有结果(失败与否)的一种常见方法是将未来的新表示失败,以便所有期货都能得到一些结果(尽管它们可能会以表示失败的结果完成) . 一个自然的方法是提升到
Try
.Twitter's implementation of futures提供了一个简单的
liftToTry
方法,但您可以使用标准库的实现执行类似的操作:现在
Future.sequence(lifted)
将在每个未来完成时完成,并将使用Try
表示成功和失败 .因此,等待一系列期货的所有原始期货的通用解决方案可能如下所示,假设执行上下文当然是隐式可用的 .
Future.sequence
生成的Future
完成时:所有期货都已成功完成,或
其中一个期货失败了
第二点是你的情况正在发生的事情,只要其中一个被包装的
Future
失败就完成了,因为包装Future
在故障情况下只能容纳一个Throwable
. 等待其他期货没有意义,因为结果将是同样的失败 .这是支持上一个答案的示例 . 使用标准的Scala API可以轻松实现此目的 .
在这个例子中,我正在创建3个期货 . 这些将分别在5秒,7秒和9秒完成 . 对
Await.result
的调用将会阻止,直到所有期货都已解决 . 一旦所有3个期货完成,a
将被设置为List(5,7,9)
并继续执行 .此外,如果在任何期货中抛出异常,
Await.result
将立即解除阻止并抛出异常 . 取消注释Exception(...)
行以查看此操作 .我们可以通过隐式类使用自己的
onComplete
方法来丰富Seq[Future[T]]
:然后,在您的特定MWE中,您可以执行以下操作:
这种解决方案的优势在于,您可以像在单个未来那样在期货序列上调用
onComplete
.