Scala:如何正确地折叠Future集合?

4

我有一段代码,用于向一组演员发送广播消息并收集他们的响应。请看下面的简化代码:

{
  val responses: Set[Future[T] = // ask a set of actors
  val zeroResult: T
  val foldResults: (T, T) => T

  //1. Future.fold(responses)(zeroResult)(foldResults)
  //2. (future(zeroResult) /: responses) { (acc, f) => for { x <- f; xs <- acc } yield foldResults(x, xs) }
} foreach {
   client ! resp(_)
}

然后我注意到代码行1和2的行为有所不同。例如,有4个actor将Traversable(1)作为响应发送,并且

zeroResult = Traversable.empty[Int]
foldResults = { _ ++ _ }

第一行的结果是不同的:通常我会得到List(1, 1, 1, 1),但有时会得到List(1, 1, 1),甚至是List(1, 1)。这对我来说并不奇怪,因为Future.fold是非阻塞的,所以可能会丢失一些响应。
但第二行总是产生四个一的列表。
有人能解释一下这些fold之间的差异以及哪种更可取吗?

折叠的原因是收集所有响应吗?如果是这样,我建议只使用Future.sequence将响应的未来列表转换为响应列表的未来,该未来将在所有响应到达或失败时完成。 - Arne Claassen
1个回答

0
在你的问题中,让我惊讶的是你的第一个折叠(因为它简洁明了)有时似乎是在一个成功完成的三个(或两个)future列表上操作。
在正常情况下,未来有三种可能的结果:
1. 正常完成 2. 失败(带异常完成) 3. 未完成
你提供的这两个折叠都将产生一个未完成的单一future,而其所有组成的futures都已完成,如果任何future(或折叠操作)失败,则会失败,如果一切顺利,则会完成。(你的句子“Future.fold是非阻塞的,所以似乎会错过一些响应”是不正确的。)
我只能想到你在其他地方有一些代码,如果某个超时被触发,就会完成没有结果的futures。
除此之外,你在第二行中交换了折叠操作数的顺序(应该是yield foldResults(xs, x)),因此最终顺序与第一行相反。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接