如何处理发出Future [T]的源代码?

时间:2016-09-28 09:45:26

标签: scala akka akka-stream

假设我有一些迭代器:

val nextElemIter: Iterator[Future[Int]] = Iterator.continually(...)


我想从迭代器构建一个源:

val source: Source[Future[Int], NotUsed] =
  Source.fromIterator(() => nextElemIter)


所以现在我的源代码发出Future个。我从来没有看到期货在Akka文档或其他任何地方的阶段之间传递,所以相反,我总是可以这样做:

val source: Source[Int, NotUsed] = 
  Source.fromIterator(() => nextElemIter).mapAsync(1)(identity /* was n => n */)


现在,我有一个常规来源,可以发出T而不是Future[T]。但这感觉很糟糕而且错了。

处理这种情况的正确方法是什么?

1 个答案:

答案 0 :(得分:5)

直接回答你的问题:我同意弗拉基米尔的评论,即对于你所描述的目的使用mapAsync没有“hacky”。我想不出更直接的方法来展开Future来自您的基础Int值。

间接回答你的问题......

尝试坚持期货

作为一种并发机制,Streams在需要背压时非常有用。但是,纯Future操作在应用程序中也占有一席之地。

如果您的Iterator[Future[Int]]将产生已知的,有限的Future个值,那么您可能希望坚持使用Futures进行并发。

想象一下,你想过滤,映射和放大减少Int值。

def isGoodInt(i : Int) : Boolean = ???         //filter
def transformInt(i : Int) : Int = ???          //map
def combineInts(i : Int, j : Int) : Int = ???  //reduce

期货提供了使用这些功能的直接方式:

val finalVal : Future[Int] = 
  Future sequence { 
    for {
      f <- nextElemIter.toSeq  //launch all of the Futures
      i <- f if isGoodInt(i)
    } yield transformInt(i)
  } map (_ reduce combineInts)

与您建议的使用Stream的某种间接方式相比:

val finalVal : Future[Int] = 
  Source.fromIterator(() => nextElemIter)
        .via(Flow[Future[Int]].mapAsync(1)(identity))
        .via(Flow[Int].filter(isGoodInt))
        .via(Flow[Int].map(transformInt))
        .to(Sink.reduce(combineInts))
        .run()