使用期货并行化scala中的递归分支计算

时间:2016-10-20 14:11:48

标签: multithreading scala concurrency

我正在尝试使用Futures在Scala中并行化SAT求解器。

解决SAT问题的算法与(伪代码)非常相似:

def has_solution(x):
    if x is a solution:
        return true
    else if x is not a solution:
        return false
    else:
        x1 = left_branch(x)
        x2 = right_branch(x)
        return has_solution(x1) or has_solution(x2)

因此,每当我解决问题时,我都会看到有机会并行计算。

我如何用期货做到这一点?我需要等待has_solution(x1)和has_solution(x2)以及:

的结果
  1. 一旦分支返回true,则返回true
  2. 如果两个分支都返回false,则返回false
  3. 我目前的做法如下:

    object DPLL {
      def apply(formula: Formula): Future[Boolean] = {
        var tmp = formula
    
        if (tmp.isEmpty) {
          Future { true }
        } else if (tmp.hasEmptyClause) {
          Future { false }
        } else {
    
          for (unitClause <- tmp.unitClauses) tmp = tmp.propagateUnit(unitClause);
          for (pureLiteral <- tmp.pureLiterals) tmp = tmp.assign(pureLiteral);
    
          if (tmp.isEmpty())
            Future { true }
          else if (tmp.hasEmptyClause)
            Future { false }
          else {
            val nextLiteral = tmp.chooseLiteral
    

    以下是分支发生的地方以及我希望等待上述计算的地方:

            for (f1 <- DPLL(tmp.assign(nextLiteral)); 
                 f2 <- DPLL(tmp.assign(-nextLiteral)))
              yield (f1 || f2)
          }
        }
      }
    }
    

    当我运行它时看起来不对,因为我永远无法完全使用我的核心(8)。

    我有一种直觉,我不应该使用期货进行这种计算。也许期货只适合异步计算。我应该尝试一些较低级别的线程或基于actor的方法吗?感谢。

1 个答案:

答案 0 :(得分:2)

由于for block,此代码按顺序工作!计算f2完成后,f1的计算开始。

for {
  f1 <- DPLL(tmp.assign(nextLiteral))
  f2 <- DPLL(tmp.assign(-nextLiteral))
} yield f1 || f2

上面的块转换为以下flatMap/map序列,flatMap/map做的是在值出现后运行该函数。

DPLL(tmp.assign(nextLiteral)).flatMap(f1 =>
  DPLL(tmp.assign(-nextLiteral)).map(f2 =>
    f1 || f2)

并行启动计算的一个简单技巧是将它们分配给一个值并访问该值以进行理解

val comp1 = DPLL(tmp.assign(nextLiteral))
val comp2 = DPLL(tmp.assign(-nextLiteral))
for {
  f1 <- comp1
  f2 <- comp1
} yield f1 || f2