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、ma​​p関数を使用して、先物を組み合わせることができます。

ただし、これは、computeFullとcomputePartialが実際の結果をラップするFuturesを返す必要があることを意味します。したがって、それらはAKKAに依存するようになり、物事が並行して実行されると想定します。実際、関数内で実行コンテキストを暗黙的に渡す必要もあります。

これは奇妙であり、アルゴリズムはそれがどのように並列化されているか、または並列化されているかどうかの詳細を「知らない」はずだと思います。

(AKKAではなく)scalaのFuturesについて読み、CodeContinuationを調べた後。scala(http://www.scala-lang.org/api/current/scala/Responder.html)によって提供されるResponderモナドは、関数呼び出しの実行方法を抽象化する正しい方法のようです。私は、computeFullとcomputePartialがfuturesではなくRespondersを返す可能性があり、モナドが実行されると、Responder内に埋め込まれたコードがどのように実行されるかを決定するという漠然とした直感を持っています(新しいアクターを生成するか、同じスレッドで実行されるか) )。

しかし、どうやってこの結果を得るのか、私にはよくわかりません。助言がありますか?私は正しい方向に進んでいると思いますか?

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

akkaの一人の俳優は、彼が平行して走るかどうかを知りません。それがakkaの設計方法です。ただし、akkaに依存したくない場合は、次のような並列コレクションを使用できます。

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

合計はparrallelコレクションで呼び出され、parrallelで実行されます。

于 2012-05-05T16:13:21.047 に答える