Scalaで並行処理#2 – AkkaのActorを使う
はじめに
前回の記事ではScala標準のActorを使用して並行処理プログラムを記述してみました。 今回はここでも少しふれたAkkaを使用してみます。
今回使用した動作環境は以下のとおりです。
- OS : MacOS X 10.7.2
- Java : 1.6.0_26
- Scala : 2.9.1 final
- SBT : 0.11.2
- Eclipse : 3.7
実行環境のセットアップ
今回はプロジェクトの作成や実行を、ScalaのビルドツールであるSimple Build Tool(以下sbt)を使用して行います。 MacであればHomebrewで簡単にインストールできるので、インストールしましょう。 それ以外の方法でインストールするのであればこのへんをみたりすればできると思います。
% brew install sbt
サンプル用プロジェクトの作成
まず適当なディレクトリを作成し(myAkkaSampleと仮定)、build.sbtという名前で下記ファイルを用意します。 ここではプロジェクト全体の設定や依存ライブラリの設定を行います。 今回はAkkaを使用するので、その設定を記述します。 ※空行も必要なので、そのとおりに入力してください
name := "My Akka Sample" version := "1.0" scalaVersion := "2.9.1" resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/" libraryDependencies += "se.scalablesolutions.akka" % "akka-actor" % "1.2" libraryDependencies += "se.scalablesolutions.akka" % "akka-remote" % "1.2" libraryDependencies += "se.scalablesolutions.akka" % "akka-stm" % "1.2"
sbtについての詳細な解説はこのあたりを参照してください。
次にソースファイルを置くディレクトリを作成します。
% cd myAkkaSample % mkdir -p src/main/scala % mkdir -p src/test/scala
このあと作成するファイルはsrc/main/scalaディレクトリの中に作成します。
Akka-Actorの基本
ではAkkaを使用したサンプルプログラムを作成してみましょう。src/main/scalaディレクトリにMyAkka.scalaファイルを作成し、Actorクラスを定義しましょう。
import akka.actor.Actor class MyAkkaActor extends Actor { def receive = { case i:Int => println("Int=" + i) case msg => { println(msg + " by MyAkkaActor") self.reply("Hello," + msg.toString) } } }
同じファイルの、MyAkkaActorの下にMainオブジェクトを記述します。 Appトレイトを実装したオブジェクトは、mainメソッドを記述しなくても起動時に内容が実行されます。
object Main extends App { //アクターを作成 val myAkkaActor = Actor.actorOf[MyAkkaActor] //アクターを開始 myAkkaActor.start() //非同期実行 val result = myAkkaActor ! 100 println("result = " + result) //同期実行 val resultOption = myAkkaActor !! "taro" resultOption match { case Some(result) => println("result=" + result) case _ => println("None") } //Futureを返す val resultFuture = myAkkaActor !!! "takeshi" resultFuture.result match { case Some(result) => println("result=" + result) case _ => println("None") } //アクターを停止 myAkkaActor.stop }
sbtを起動して実行してみましょう。下記のような結果になるはずです。
% sbt > run [info] Running Main result = () Int=100 taro by MyAkkaActor result=Hello,taro None takeshi by MyAkkaActor [success] Total time: 1 s, completed 2012/01/20 17:31:11
まずはMyAkkaActorの説明です。Scala標準のActorを使用したときとの違いは下記のようになっています。
- scala.actors.Actorではなく、akka.actor.Actorを継承する
- actメソッドでなく、receiveメソッドを実装する
- loopブロックを使用していないが、loop状態になっている
- Actor自身に定義された関数にアクセスするためにself(自身を含むActorRefのインスタンス)を使用している
そしてMyAkkaActorを使用するコード部分ですが、startでActor開始、stopでActorを停止します。 メッセージパッシングの動作において、!で非同期実行は同じですが、同期実行は!?でなく!!になっており、戻り値はOption型です。 また、以前!!で記述していた処理は、!!!で記述し、戻り値はakka.dispatch.ActorCompletableFuture型です。
それ以外に、MyAkkaActorに対してreplyを返さないケースの同期メッセージを贈った場合、(myAkkaActor !! 100) 標準のActorだとそのまま待ち続けてしまいますが、Akkaではデフォルトで5秒たつとOption[None]が返ります。
まとめ
今回はAkkaを使用してActorの基本的なプログラムを記述してみました。 Scala標準のActorと微妙に似ている箇所もあるので気をつけてください。 これ以外にもAkkaはさまざまな機能を持っていますので、次回以降ご紹介できればと思います。
参考サイトなど
- Scalaで並行処理#1 - Actorを使う:https://dev.classmethod.jp/server-side/scala-actor/
- Typesafe StackをインストールしてScala/Akkaの開発環境を作ろう:https://dev.classmethod.jp/etc/typesafestack/
- はじめるsbt:http://eed3si9n.github.com/sbt-getting-started-guide-ja/