我正在使用scala(2.12)期货对复杂问题采用并行分而治之的方法。这是一些(简化的)上下文:
def solve(list: List[Int], constraints: Con): Future[Boolean] =
Future.unit.flatMap{ _ =>
//positive case
if(list.isEmpty) Future.successful(true)
//negative case
else if(someTest(constraints)) Future.successful(false)
//divide and conquer
else {
//split to independent problems, according to constraints
val components: List[List[Int]] = split(list,constraints)
//update the constraints accordingly (heavy computation here)
val newConstr: Con = updateConstr(...)
val futureList = components.map(c => solve(c,newConstr))
allTrue(Future.successful(true), futureList)
}
}
此递归函数采用整数变量列表和表示问题约束的Con
对象,并在每次调用期间产生多个独立的子问题。
我的问题的相关部分是对allTrue
的调用。如果我按顺序解决问题,我会写components.forall(c => solve(c,newConstr))
。然而,在并发版本中,我有类似的东西
这,它不会在遇到的第一个false
情况下停止计算。
//async continuation passing style "forall"
def allTrue(acc: Future[Boolean], remaining: List[Future[Boolean]]):
Future[Boolean] = {
remaining match {
case Nil => acc
case r :: tail => acc.flatMap{ b =>
if(b) allTrue(r,tail)
else{
//here, it would be more efficient to stop all other Futures
Future.successful(false)
}
}
}
}
我已经阅读了多篇博客文章和论坛帖子,讨论如何阻止scala期货通常不是一个好主意,但在这种情况下我认为它会非常有用。
关于如何在期货清单上获得forall
行为的任何想法?
答案 0 :(得分:2)
不停止期货的简单方法是Future.traverse
val all:Future[List[Boolean]] = Future.traverse(components)(c => solve(c, newConstr)
val forAll:Future[Boolean] = all.map(_.forall(identity))
对于可取消的期货清单,我建议您查看Observable模式。在您的情况下,订户可以在看到False值时取消订阅,生产者将在没有订阅者监听时停止计算