我遇到需要并行运行一堆操作的情况。
所有操作都具有相同的返回值(例如Seq[String]
)。
某些操作可能会失败,而其他操作可能会成功返回结果。
我想同时返回成功的结果和发生的任何异常,因此我可以将它们记录下来进行调试。
在我编写自己的类来执行此操作之前,是否有内置方法或通过任何库(cats / scalaz)进行访问的简便方法?
我正在考虑在自己的将来进行每个操作,然后检查每个将来,并返回一个Seq[String] -> Seq[Throwable]
元组,其中左边的值是成功的结果(展平/合并),右边的是任何异常的列表发生了。
有更好的方法吗?
答案 0 :(得分:2)
使用Await.ready
(您在评论中提到)通常会失去使用期货的大部分好处。相反,您可以仅使用常规的Future
组合器来执行此操作。让我们做一个更通用的版本,它适用于任何返回类型。扁平化Seq[String]
可以轻松添加。
def successesAndFailures[T](futures: Seq[Future[T]]): Future[(Seq[T], Seq[Throwable])] = {
// first, promote all futures to Either without failures
val eitherFutures: Seq[Future[Either[Throwable, T]]] =
futures.map(_.transform(x => Success(x.toEither)))
// then sequence to flip Future and Seq
val futureEithers: Future[Seq[Either[Throwable, T]]] =
Future.sequence(eitherFutures)
// finally, Seq of Eithers can be separated into Seqs of Lefts and Rights
futureEithers.map { seqOfEithers =>
val (lefts, rights) = seqOfEithers.partition(_.isLeft)
val failures = lefts.map(_.left.get)
val successes = rights.map(_.right.get)
(successes, failures)
}
}
Scalaz and Cats have separate
to simplify the last step.
编译器可以推断出类型,它们的显示只是为了帮助您了解逻辑。
答案 1 :(得分:1)
听起来像Try
惯用法的好用例(它基本上与Either
单子相似)。
doc中的用法示例:
import scala.util.{Success, Failure}
val f: Future[List[String]] = Future {
session.getRecentPosts
}
f onComplete {
case Success(posts) => for (post <- posts) println(post)
case Failure(t) => println("An error has occurred: " + t.getMessage)
}
它实际上比您要求的功能多一点,因为它是完全异步的。是否适合您的用例?
答案 2 :(得分:1)
在value
上调用Future
会返回Option[Try[T]]
。如果Future
尚未完成,则Option
为None
。如果已完成,则很容易解包和处理。
if (myFutr.isCompleted)
myFutr.value.map(_.fold( err: Throwable => //log the error
, ss: Seq[String] => //process results
))
else
// do something else, come back later
答案 3 :(得分:0)
我会这样:
<id>machine</id>
<modules>
<module>../test1</module>
<module>../test2</module>
<module>../test3</module>
</modules>