2012-05-05 5 views
0

明らかに並列化可能なアルゴリズムを管理するためにscalaとAKKAを検討してきました。 私は関数型プログラミングに関する知識があり、ほとんどがJavaを使用していますので、私のFPはまだ最善ではないかもしれません。Scala、Responderを使用して非同期計算を抽象化する

私が働いているアルゴリズムは非常に簡単です、トップ計算があります:

def computeFull(...): FullObject 

この計算は、それを総括その後、サブ計算を呼び出し、(簡単にするために):

def computePartial(...): Int 

と私は、

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

ので:computeFullはこのような何か(再単純化)を行いますtはPI計算を行うAKKAの例に非常に近い。私は多くのcomputePullを呼び出して、それぞれの中にcomputePartialをたくさん持っています。だから私はこれをAKKAの俳優で包んだり、Futuresで単純化して、それぞれのcomputeFullとcomputePartialを別々のスレッドで呼び出すことができます。私はその後、先物を組み合わせるために、http://doc.akka.io/docs/akka/snapshot/scala/futures.htmlの折り畳み、ジップ、およびマップ機能を使用することができます。

しかし、これは、computeFullとcomputePartialが実際の結果をラッピングするFuturesを返さなければならないことを意味します。したがって、彼らはAKKAに依存し、物事は並行して実行されると仮定します。実際には、自分の関数内で実行コンテキストを暗黙的に伝えなければなりません。

私はこれが奇妙で、アルゴリズムは並列化されているかどうかの詳細を知ってはいけないと思います。

先物についてスカラーで(AKKAではなく)読んでコード継続を調べた後。 scala(http://www.scala-lang.org/api/current/scala/Responder.html)によって提供されるレスポンダモナドが、関数呼び出しの実行方法を抽象化する正しい方法のように思えます。 私はcomputeFullとcomputePartialが未来の代わりにレスポンダを返すことができ、モナドが実行されたときにレスポンダ内に埋め込まれたコードがどのように実行されるかを決定するという曖昧な直感を持っています(新しいアクタを生成するか、糸)。

しかし、私はこの結果に到達する方法が本当にわかりません。助言がありますか?私は正しい方法でいると思いますか?

答えて

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の準備が整うまで、これはブロックされますので、あなたが本当に先物を必要とするときは、適切な状況ではないかもしれません。

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は、それが実行されているかについて何を知っている必要はありません:あなたはあなたのアルゴリズムは今までそれに気付かず、その完全に非同期を作ることができるのScala 2.10スタイル先物で

。 (たとえこの例の目的のために副作用があってはならないが、副作用printlnが含まれていました。)

可能なcomputeFullメソッドは、Futuresまたは並列性について知っているアルゴリズムを管理する必要があります。結局のところ、このアルゴリズムの一部です。

Responderについて:。?Scalaの古い先物は、それを使用するこれが起こっている場所を私は知らない - そして、コンフィギュレーションの実行コンテキストではありません正確な手段あなたが探している)

+0

いいね、私は公式の2.10を見ています。しかし、私はAKKAから独立した方法ではなく、どのようにcomputePartial/computeFullをFuturesに忘れて残すべきか、私が疑問に思っていたことは明らかではないかもしれません。あなたのようなビットは、依存関係注入を行うためにReaderモナドを使用しますが、DB接続を下げる代わりに、関数を実行するための戦略を渡します:並列かどうか、完全に異なるもの。したがって、これらの2つのメソッドのコードを変更することなく、異なる並列化オプションを比較することができます。 – Mortimer

0

akkaの一人の俳優は、彼がparrallelで動いたかどうかは分かりません。それがakkaの設計方法です。

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

合計がparrallelコレクションで呼び出され、parrallelで行われます。しかし、あなたはあなたのようなparrallelコレクションを使用することができますアッカに依存したくない場合。

関連する問題