タイプセーフスタック2.0のレビューと、Akka 2.0を例として使用したアクターモデルの紹介

画像



タイプセーフスタック-JavaおよびScalaで簡単にスケーラブルなソフトウェアシステムを作成する機能を提供する最新のソフトウェアプラットフォーム。 スタックは、 Akka 2.0およびPlayframework 2.0フレームワークを含むJVM上で実行されます。 開発されたシステムの実質的に無制限のスケーラビリティを提供するプラットフォームのコアは、アクターライブラリであり、これはアクターモデルに基づいてマルチタスクを実装します。



俳優モデル


アクターモデルの厳密な定義、およびその歴史と基本的な概念は、 Wikipediaで見つけることができます。 つまり、アクターモデルは、周囲のすべてがアクターであるという哲学に基づいています。 これは、オブジェクト指向プログラミングの哲学に似ていますが、唯一の違いは、アクターモデルでは、原則としてオブジェクト指向プログラミングのようにプログラムが順次実行される場合、計算が本質的に時間的に一致することです。 アクターモデルには共有状態がなく、データは、あるアクターから別のアクターへのメッセージパッシングメカニズムを使用して交換されます。 各アクターには、受信メッセージのキューがあり、順番に処理されます。 共有状態がなく、メッセージが順次処理されるため、アクターモデルに基づくプログラムの計算の並列化が大幅に簡素化され、そのようなプログラムの信頼性が向上します。



あか


前述のとおり、AkkaはJVMにアクターモデルを実装します。 それ以外の場合、アクターはライトスレッド(緑のスレッド)と呼ばれます。 このようなフローは非常に軽量で、その数は1 GBのRAMあたり約270万に達し、1つのノードで送信されるメッセージの数は2,000万/秒を超えます。 ネットワークを介してアクターの相互作用を整理する可能性があり、開発されたアプリケーションの拡張性はほぼ無限になります。 Akkaの機能の詳細については、 公式Webサイトを参照してください



タイプセーフとAkkaの例


オリジナル: ここ



Typesafe StackでAkkaを使い始めるのはとても簡単です。 セットアッププロセスはスタックディストリビューションのダウンロードとインストールになります。 開発にはJavaとScalaの両方を使用できますが、後者を使用すると、プログラムが特にスリムで読みやすく、理解しやすくなるため、以下の例ではScalaを使用します。



問題の声明


この例では、アクターを使用してPIの数の値を計算します。 この操作ではプロセッサを集中的に使用するため、Akkaを使用すると、マルチコアマシンでスケーラブルな並列コンピューティングを実装できます。 使用されるアルゴリズムは十分に並列化されています。 各計算は独立しており、アクターモデルに完全に投影されます。 計算の式は次のとおりです。



画像



メインアクターはこのシリーズをコンポーネントに分割し、計算のために各メンバーを補助アクターに送信します(シリーズの各メンバーに1つの補助アクター)。 計算が完了すると、各補助アクターは結果を主アクターに返します。 すべての計算の結果を受け取った後、メインアクターが回答を作成します。



プロジェクト作成


まず、 giter8テンプレートからプロジェクトを作成する必要があります(Typesafe Stackをインストールする必要があります):

c:\temp>g8 typesafehub/akka-scala-sbt



Akka 2.0 Project Using Scala and sbt



organization [org.example]: akka.tutorial

package [org.example]: akka.tutorial.first.scala

name [Akka Project In Scala]: PI Calculator

akka_version [2.0]:

version [0.1-SNAPSHOT]:



Applied typesafehub/akka-scala-sbt.g8 in pi-calculator







プロジェクトが作成されたので、プロジェクトフォルダーに移動します。

c:\temp>cd pi-calculator







コードの書き始め


まず、適切なフォルダー( ./src/main/scala/akka/tutorial/first/scala/



)に./src/main/scala/akka/tutorial/first/scala/



ファイルを作成し、必要なライブラリーをインポートする必要があります。

import akka.actor._

import akka.routing.RoundRobinRouter

import akka.util.Duration

import akka.util.duration._







メッセージテンプレートの作成


上記で簡単に説明したアプリケーションのアーキテクチャを明確にします。 多くのWorker



アクターを作成し、計算を初期化するMaster



アクターが1つあります。 これを行うために、彼はタスク全体を小さな操作に分割し、これらの操作をアクターのWorker



送信します。 操作を実行した後、 Worker



アクターは集計の結果を返します。 計算が完了すると、 Master



アクターはListener



結果をアクターに送信し、アクターはそれを画面に表示します。



この説明に基づいて、システムで送信されるメッセージを作成します。



一般的な可変状態を排除するために、アクターに送信されるメッセージは不変でなければなりません。 Scalaでは、ケースクラスがこれに最適です。 また、メッセージの共通の基本特性を作成します。これは、メッセージの無制限な追加を防ぐために封印済みとして指定します。

封印された特性PiMessage
ケースオブジェクトCalculateはPiMessageを拡張します
ケースクラスWork(開始:Int、nrOfElements:Int)はPiMessageを拡張します
ケースクラスResult(値:Double)はPiMessageを拡張します
ケースクラスPiApproximation(pi:Double、duration:Duration)


Worker



アクターの作成


これでWorker



アクターを作成できます。 これは、 Actor



トレイトを混合し、 receive



メソッドを定義するreceive



によって行われます。 このメソッドは着信メッセージハンドラです。

クラスWorkerはActorを拡張します{

   // CalculatePiFor ...

   def receive = {
    ケース作業(開始、nrOfElements)⇒
      送信者!  Result(calculatePiFor(start、nrOfElements))//作業を実行
   }
 }


ご覧のとおり、 Work



メッセージハンドラーを追加しました。これは、 calculatePiFor



操作の完了後にResult



応答メッセージを作成し、送信者に送り返します。 次に、 calculatePiFor



を実装しcalculatePiFor





 def calculatePiFor(開始:Int、nrOfElements:Int):Double = {
   var acc = 0.0
   for(i←start until(start + nrOfElements))
     acc + = 4.0 *(1-(i%2)* 2)/(2 * i + 1)
   acc
 }




Master



アクターの作成


Master



アクターはもう少し複雑です 彼のコンストラクターでは、 Worker



アクター間の操作の分散を容易にするために循環ルーターが作成されます。

 val workerRouter = context.actorOf(
  小道具[Worker] .withRouter(RoundRobinRouter(nrOfWorkers))、name = "workerRouter")


ここで、 Master



アクター自身を作成し​​ます。 このアクターは、次のパラメーターで作成されます。



したがって、次のコードがあります。

クラスマスター(nrOfWorkers:Int、 
   nrOfMessages:Int、 
   nrOfElements:Int、 
  リスナー:ActorRef)Actorを拡張する{

   var pi:Double = _
   var nrOfResults:Int = _
   val start:Long = System.currentTimeMillis

   val workerRouter = context.actorOf(
    小道具[Worker] .withRouter(RoundRobinRouter(nrOfWorkers))、name = "workerRouter")

   def receive = {
     //メッセージを処理します...
   }

 }


上記のパラメーターに加えて、 Listener



アクターへの参照であるActorRef



オブジェクトがMaster



アクターに渡されます。 アクター間のメッセージの転送は、常にこのようなリンクを介して実行されることに注意してください。



しかし、それだけではありません。なぜなら メッセージハンドラーは実装しませんでした。これを作成します。

 def receive = {
  計算⇒
     for(i←nrOfMessagesまで0) 
       workerRouter! 作業(i * nrOfElements、nrOfElements)
  ケース結果(値)⇒
     pi + =値
     nrOfResults + = 1
     if(nrOfResults == nrOfMessages){
       //結果をリスナーに送信します
      リスナー!  PiApproximation(pi、duration =(System.currentTimeMillis-start).millis)
       //このアクターとそのすべての監視対象の子を停止します
       context.stop(自己)
     }
 }


一般に、コードは明確である必要があります。計算が完了し、結果が出力された後、 context.stop(self)



コマンドでMaster



アクターが停止されることに注意してください。



Listener



アクターの作成


このアクターの実装は非常に簡単です。 Master



アクターからPiApproximation



メッセージを受け取り、結果を出力し、アクターシステムを停止します。

クラスリスナーはアクターを拡張します{
   def receive = {
    ケースPi近似(pi、期間)⇒
       println( "\ n \ tPi近似:\ t \ t%s \ n \ t計算時間:\ t%s"
         .format(pi、期間))
       context.system.shutdown()
   }
 }




アプリケーションオブジェクトの作成


これで、アプリケーションオブジェクトを記述するだけで、プログラムの準備が整いました。

オブジェクトPiはAppを拡張します{

  計算(nrOfWorkers = 4、nrOfElements = 10000、nrOfMessages = 10000)

   //アクターとメッセージ...

   def compute(nrOfWorkers:Int、nrOfElements:Int、nrOfMessages:Int){
     // Akkaシステムを作成します
     val system = ActorSystem( "PiSystem")

     //結果を作成し、結果を出力します 
     //システムをシャットダウンします
     val listener = system.actorOf(Props [リスナー]、名前= "リスナー")

     //マスターを作成します
     val master = system.actorOf(Props(new Master(
       nrOfWorkers、nrOfMessages、nrOfElements、listener))、
       name = "master")

     //計算を開始します
    マスター! 計算する

   }
 }




アプリケーションの起動


sbtからアプリケーションを実行する最も簡単な方法。 これを行うには、アプリケーションのあるフォルダーに移動して、 sbt



コマンドを入力します。 次に、次の一連のコマンドを実行します。

c:\temp\pi-calculator>sbt

[info] Loading project definition from C:\temp\pi-calculator\project

[info] Set current project to PI Calculator (in build file:/C:/temp/pi-calculator/)

> compile

[success] Total time: 0 s, completed 20.03.2012 16:33:03







> run

[info] Running akka.tutorial.first.scala.Pi



Pi approximation: 3.1415926435897883

Calculation time: 423 milliseconds

[success] Total time: 1 s, completed 20.03.2012 16:33:25







アクターの数を1に減らすと、結果が変わります。

> run

[info] Running akka.tutorial.first.scala.Pi



Pi approximation: 3.1415926435897883

Calculation time: 1160 milliseconds

[success] Total time: 2 s, completed 20.03.2012 16:35:16







8に増やすと、結果は次のようになります。

> run

[info] Running akka.tutorial.first.scala.Pi



Pi approximation: 3.1415926435897905

Calculation time: 388 milliseconds

[success] Total time: 1 s, completed 20.03.2012 16:36:55







テストが4核機械で実行された場合、結果は予測可能です。 したがって、アクターの数を16に増やしてもパフォーマンスはほとんど向上しません。

> run

[info] Running akka.tutorial.first.scala.Pi



Pi approximation: 3.141592643589789

Calculation time: 372 milliseconds

[success] Total time: 1 s, completed 20.03.2012 16:40:04







Play 2.0に関する投稿は近日中に公開されます。 頑張って



All Articles