假设我有一些迭代器:
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]
。但这感觉很糟糕而且错了。
处理这种情况的正确方法是什么?
答案 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()