问题描述
我正在寻找一种将任意长度的Futures列表转换为List of Future的方法.我正在使用Playframework,所以最终,我真正想要的是一个Future[Result]
,但是为了简化起见,我们只说Future[List[Int]]
即可.通常的方法是使用Future.sequence(...)
,但有一点不同.我给出的列表通常包含大约10到20个期货,并且其中一种期货失败(它们正在发出外部Web服务请求)并不罕见.如果希望其中一个失败,则不必重试所有这些,而我希望能够找到成功的并返回它们.
I'm looking for a way to convert an arbitrary length list of Futures to a Future of List. I'm using Playframework, so ultimately, what I really want is a Future[Result]
, but to make things simpler, let's just say Future[List[Int]]
The normal way to do this would be to use Future.sequence(...)
but there's a twist... The list I'm given usually has around 10-20 futures in it, and it's not uncommon for one of those futures to fail (they are making external web service requests). Instead of having to retry all of them in the event that one of them fails, I'd like to be able to get at the ones that succeeded and return those.
例如,执行以下操作无效
For example, doing the following doesn't work
import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.Success
import scala.util.Failure
val listOfFutures = Future.successful(1) :: Future.failed(new Exception("Failure")) ::
Future.successful(3) :: Nil
val futureOfList = Future.sequence(listOfFutures)
futureOfList onComplete {
case Success(x) => println("Success!!! " + x)
case Failure(ex) => println("Failed !!! " + ex)
}
scala> Failed !!! java.lang.Exception: Failure
我希望能够将1和3从那里拉出来,而不是得到唯一的例外.我尝试使用Future.fold
,但是显然只是在后台调用Future.sequence
.
Instead of getting the only the exception, I'd like to be able to pull the 1 and 3 out of there. I tried using Future.fold
, but that apparently just calls Future.sequence
behind the scenes.
提前感谢您的帮助!
推荐答案
诀窍是首先确保所有期货都没有失败. .recover
是您的朋友,您可以将其与map
组合以将所有Future[T]
结果转换为Future[Try[T]]]
实例,所有这些实例肯定是成功的未来.
The trick is to first make sure that none of the futures has failed. .recover
is your friend here, you can combine it with map
to convert all the Future[T]
results to Future[Try[T]]]
instances, all of which are certain to be successful futures.
注意:您也可以在这里使用Option
或Either
,但是如果您特别想捕获异常,则Try
是最干净的方法
note: You can use Option
or Either
as well here, but Try
is the cleanest way if you specifically want to trap exceptions
def futureToFutureTry[T](f: Future[T]): Future[Try[T]] =
f.map(Success(_)).recover { case x => Failure(x)}
val listOfFutures = ...
val listOfFutureTrys = listOfFutures.map(futureToFutureTry(_))
然后像以前一样使用Future.sequence
,为您提供Future[List[Try[T]]]
Then use Future.sequence
as before, to give you a Future[List[Try[T]]]
val futureListOfTrys = Future.sequence(listOfFutureTrys)
然后过滤器:
val futureListOfSuccesses = futureListOfTrys.map(_.filter(_.isSuccess))
如果需要,您甚至可以排除特定的故障:
You can even pull out the specific failures, if you need them:
val futureListOfFailures = futureListOfTrys.map(_.filter(_.isFailure))
这篇关于Scala:忽略失败的期货,将[未来]列出到[期货]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!