5

如果两个表达式 e1 和 e2 只处理不可变的数据结构,那么并行计算元组 (e1, e2) 应该非常简单,只需在不同的处理器上计算这两个表达式,不要担心任何交互,因为应该不是。

Scala 有很多不可变的数据结构,所以我希望有一种超级简单(编写)的方式来并行评估该元组。就像是

par_tuple : ( Unit -> T1) -> (Unit -> T2) -> (T1, t2)

它并行评估两个函数并在两者都完成时返回。

不过,我还没有看到它。它存在吗?如果不是,你会怎么写?

4

1 回答 1

6

这取决于被评估的表达式的成本。在当前的架构上,两个表达式涉及几条到几十条甚至数百条指令,无法有效地并行计算。因此,您应该始终确保您正在执行的工作量不会被并行化本身的成本所掩盖。

考虑到这个免责声明,在 Scala 2.10 中,您可以使用Futures 来完成此操作:

val f = future { e1 }
val g = future { e2 }
(Await.result(f), Await.result(g))

请注意,不鼓励这种类型的计算(上面故意过于冗长!),因为它涉及阻塞,并且在没有有效延续概念的 JVM 等平台上阻塞通常代价高昂(尽管在它的适用范围超出了这个答案的范围,可能也超出了这个回答者的范围)。在大多数情况下,您应该在 future 上安装一个回调,一旦它的值可用,就会调用它。你可以这样做:

val h = for {
  x <- f
  y <- g
} yield (x, y)

上面是h一个新的未来,一旦两者都可用,它将包含一个值元组。

您可以将函数重写par_tuple为:

def par_tuple[E1, E2](e1: =>E1, e2: =>E2): Future[(E1, E2)] = {
  val f = future { e1 }
  val g = future { e2 }
  val h: Future[(E1, E2)] = for {
    x <- f
    y <- g
  } yield (x, y)
  h
}

这个方法返回一个Future你想要的元组——一个最终将用你的表达式保存元组的对象。你可以用其他计算进一步组合这个未来,或者如果你确定要阻止,你可以有另一个变体:

def par_tuple_blocking[E1, E2](e1: =>E1, e2: =>E2): (E1, E2) = Await.result(par_tuple(e1, e2))

在元组将来可用之前阻塞。

在此处查看有关期货、回调和阻塞的更多信息

于 2012-10-16T21:23:21.567 回答