我正在进行昂贵的计算,我是批处理的,并返回分块的HTTP响应。定期有一些计算比其他计算更贵[&34;它可能会导致客户端超时。
目前Enumerator中的计算列表如下:
def processBatch(batch: List[B]): Enumerator[A] = {
val listOfCalculations:List[Future[A]] = batch.map(....)
val futureList: Future[List[A]] = Future.sequence(listOfFutures)
Enumerator.flatten(futureList.map(Enumerator.enumerate(_)))
}
通过此实现,Enumerator仅在Future列表完成后才输入。这样做并不好,因为可能存在一些现成值,等待昂贵的任务完成。
我想知道是否有更好的方法可以做到这一点 - 只要它们在完成时就向Enumerator提供值,而不是作为一个批次,在所有Futures complition上?
答案 0 :(得分:2)
Future.sequence意味着"所有这些未来的清单,当它们完成时#34;所以你不能使用它。
有一种方法可以在play.api.libs.iteratee.Concurrent.unicast
中找到一个更有必要的枚举器,你可以使用它,所以一旦得到结果,就会将它推入a Channel
。这将代表命令式推送,作为一个可以使用iteratee使用的枚举器。
这样第一个完整的结果首先到达等。
答案 1 :(得分:1)
您可以使用Enumerator.unfoldM
。类似的东西:
val listOfCalculations:List[Future[A]] = ...
Enumerator.unfoldM(0) { i =>
if(i < listOfCalculations.length)
listOfCalculations(i).map(a => Some((i + 1, a)))
else Future.successful(None)
}
这有点像折叠。 i
跟踪我们在列表中的位置;每次调用我们的映射器时,我们都会从列表中获得下一个未来并使用新索引返回它。