2015-06-30 50 views
5

我有一个Promises的集合。我一直在寻找一种有效的方法来组成结果Futures。目前,我发现把它们结合在一起最彻底的方法是使用一个scalaz Monoid,就像这样:如何撰写“期货”清单?

val promises = List(Promise[Unit], Promise[Unit], Promise[Unit]) 

    promises.map(_.future).reduce(_ |+| _).onSuccess { 
    case a => println(a) 
    } 

    promises.foreach(_.success(())) 

有没有干净的方式来做到这一点并不需要scalaz?

集合中Futures的数量会有所不同,并且大量中间集合是不可取的。

+0

你介意聚合'期货'而不是'承诺'吗? –

+0

这就是我在这里做的,我用.map() –

回答

7

你可以使用Future.traverse

import scala.concurrent.ExecutionContext.Implicits.global 
import scala.concurrent.{ Future, Promise } 

val promises = List(Promise[Unit], Promise[Unit], Promise[Unit]) 
Future.traverse(promises)(_.future) 

这会给你一个Future[List[Unit]],这并不完全符合“很多中间集合”,但未必是理想的,无论是。 Future.reduce也可以工作:

Future.reduce(promises.map(_.future))((_, _) =>()) 

这会返回一个Future[Unit],这将是满足的时候所有的期货满意。

+0

鉴于它构建了一个集合,我想知道这个monoid是否更有效。但是,谢谢,这正是我正在寻找的 - 显然我不知道如何使用API​​文档,因为我从未点击未来的对象版本。 –

+0

'reduce'不会创建一个集合,所以它应该至少和monoid一样有效(可能更多)。 –

+0

是的,以及我在上面的例子中使用reduce,加快或者不会取决于你用'| + |'替换了什么。遍历创建一个列表,所以我认为这可能会带来一些小的开销。我只有少量的期货,所以名单很短,可能并不重要。 –

3

Future.sequence是你想要的方法。

+0

提取期货'Future.traverse'可能更有意义(请参阅我的答案),但仍会创建至少一个不必要的中间集合。 –

+0

序列简化遍历,所以你都是对的,但我只能接受一个。抱歉。 –

+0

在这种情况下,'traverse'实际上既简单又高效 - 它将必要的'map'和'sequence'组合成一个单独的操作。 –