【问题标题】:How to carry on executing Future sequence despite failure?尽管失败,如何继续执行 Future 序列?
【发布时间】:2013-03-24 10:31:50
【问题描述】:

Future 对象的 traverse 方法在第一次失败时停止。我想要这个方法的宽容/宽容版本,在发生错误时继续执行序列的其余部分。

目前我们在 utils 中添加了以下方法:

def traverseFilteringErrors[A, B <: AnyRef]
                           (seq: Seq[A])
                           (f: A => Future[B]): Future[Seq[B]] = {
  val sentinelValue = null.asInstanceOf[B]
  val allResults = Future.traverse(seq) { x =>
    f(x) recover { case _ => sentinelValue }
  }
  val successfulResults = allResults map { result =>
    result.filterNot(_ == sentinelValue)
  }
  successfulResults
}

有没有更好的方法来做到这一点?

【问题讨论】:

    标签: scala concurrency future


    【解决方案1】:

    真正有用的东西(一般来说)是能够将未来的错误提升为适当的价值。或者换句话说,将Future[T] 转换为Future[Try[T]](成功的返回值变为Success[T],而失败的情况变为Failure[T])。以下是我们可以如何实现它:

    // Can also be done more concisely (but less efficiently) as:
    // f.map(Success(_)).recover{ case t: Throwable => Failure( t ) }
    // NOTE: you might also want to move this into an enrichment class
    def mapValue[T]( f: Future[T] ): Future[Try[T]] = {
      val prom = Promise[Try[T]]()
      f onComplete prom.success
      prom.future
    }
    

    现在,如果您执行以下操作:

    Future.traverse(seq)( f andThen mapValue )
    

    您将获得一个成功的Future[Seq[Try[A]]],其最终值包含每个成功未来的Success 实例,以及每个失败的未来的Failure 实例。 如果需要,您可以在此 seq 上使用 collect 删除 Failure 实例并仅保留成功的值。

    换句话说,您可以如下重写您的辅助方法:

    def traverseFilteringErrors[A, B](seq: Seq[A])(f: A => Future[B]): Future[Seq[B]] = {
      Future.traverse( seq )( f andThen mapValue ) map ( _ collect{ case Success( x ) => x } )
    }
    

    【讨论】:

    • 酷。您能否评论一下为什么替代方案 (f.map(Success...) 效率较低?
    • 因为maprecover 创建Promise 的实例并返回它们关联的Future。那是两个Promise 实例,而不仅仅是一个用于我的替代解决方案。此外,“简洁”版本解开Try 实例(存储在Promise 实例中)只是为了立即将其重新包装为SuccessFailure 实例,这有点浪费。当然,您需要进行概要分析,看看它是否真的会产生任何有意义的差异。
    • 谢谢!这真的很有帮助。
    • “andThen”组合子实际上是有副作用的,因此当您应用它时,您最终会得到与原始未来相同的类型。上面的例子实际上应该类似于Future.traverse(m) { mapValue } map ( _ collect{ case Success( x ) =&gt; x } )
    • 你错了。这是Function1.andThen,不是Future.andThen
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多