0

我一直在研究 scala 和 AKKA 来管理一个明显可并行化的算法。我有一些函数式编程的知识,并且主要使用 Java,所以我的 FP 可能还不是最好的。

我正在使用的算法非常简单,有一个顶级计算:

  def computeFull(...): FullObject

此计算调用子计算,然后将其汇总(以简化):

  def computePartial(...): Int

computeFull做这样的事情(再次简化):

 val partials = for(x <- 1 to 10
     y <- 1 to 10) yield computePartial(x, y)
 partials.foldLeft(0)(_ + _)

因此,它非常接近 AKKA 示例,进行 PI 计算。我有很多 computeFull 可以调用,并且每个里面都有很多 computePartial。所以我可以将所有这些包装在 AKKA 演员中,或者在 Futures 中简化,在单独的线程中调用每个 computeFull 和每个 computePartial。然后我可以使用http://doc.akka.io/docs/akka/snapshot/scala/futures.html的 fold、zip 和 map 函数来组合期货。

但是,这意味着 computeFull 和 computePartial 必须返回包含实际结果的 Futures。因此,他们变得依赖于 AKKA,并假设事情是并行运行的。事实上,我还必须在我的函数中隐式传递执行上下文。

我认为这很奇怪,算法“不应该”知道它是如何并行化的细节,或者它是否是。

在阅读了 scala 中的 Futures(而不是 AKKA 的)并查看了代码延续之后。scala (http://www.scala-lang.org/api/current/scala/Responder.html) 提供的 Responder monad 似乎是抽象函数调用如何运行的正确方法。我有这种模糊的直觉,computeFull 和 computePartial 可以返回 Responders 而不是期货,并且当执行 monad 时,它决定嵌入在 Responder 中的代码如何执行(如果它产生一个新的 actor 或者它是否在同一个线程上执行)。

但是,我不确定如何得到这个结果。有什么建议么?你认为我走对了吗?

4

2 回答 2

3

如果您不想依赖 Akka(但请注意,Akka 风格的期货将被移动并包含在 Scala 2.10 中)并且您的计算是对集合的简单折叠,您可以简单地使用 Scala 的并行集合:

val partials = for { x <- (1 to 10).par
  y <- 1 to 10
} yield computePartial(x, y)
// blocks until everything is computed
partials.foldLeft(0)(_ + _)

当然,这将阻塞直到partials准备就绪,因此当您真正需要期货时,它可能不是一个合适的情况。

使用 Scala 2.10 风格的期货,你可以让它完全异步,而你的算法不会注意到它:

def computePartial(x: Int, y: Int) = {
  Thread.sleep((1000 * math.random).toInt)
  println (x + ", " + y)
  x * y
}

import scala.concurrent.future
import scala.concurrent.Future
val partials: IndexedSeq[Future[Int]] = for {
  x <- 1 to 10
  y <- 1 to 10
} yield future(computePartial(x, y))

val futureResult: Future[Int] = Future.sequence(partials).map(_.fold(0)(_ + _))

def useResult(result: Int) = println(s"The sum is $result")

// now I want to use the result of my computation
futureResult map { result => // called when ready
  useResult(result)
}
// still no blocking
println("This is probably printed before the sum is calculated.")

所以,computePartial不需要知道它是如何执行的。(尽管它不应该有任何副作用,即使出于本示例的目的,println也包括了副作用。)

一种可能的computeFull方法应该管理算法并因此了解Futures并行性。毕竟这算法的一部分。

(至于Responder: Scala 的旧期货使用它,所以我不知道这是怎么回事。 - 执行上下文不正是您正在寻找的配置方式吗?)

于 2012-05-05T16:05:27.103 回答
0

The single actor in akka knows not if he runs in parrallel or not. That is how akka is designed. But if you don't want to rely on akka you can use parrallel collections like:

for (i <- (0 until numberOfPartialComputations).par) yield (
  computePartial(i)
).sum

The sum is called on a parrallel collection and is performed in parrallel.

于 2012-05-05T16:13:21.047 回答