アクターライブラリ その1

Scala には、マルチスレッド処理を簡素に実現できる Actor ライブラリがあります。Actor ライブラリは、Actor 間でのメッセージのやり取りが処理をブロックすることなく行うことができます。

簡単な非同期メッセージの送信と受信

まずは簡単な例で動作を確認してみます。Actor として Friend を作成し、Hi というメッセージと Bye というメッセージを送信してみます。

import scala.actors.Actor
import scala.actors.Actor._

case object Hi  //メッセージをケースクラスとして定義
case object Bye //メッセージをケースクラスとして定義

class Friend extends Actor {
  def act() {
    while(true) {
      receive {
        case Hi =>  println("Friend: hello")
        case Bye => println("Friend: bye"); exit()
      }
    }
  }
}

object Main extends Application {
  val friend = new Friend
  friend.start
  friend ! Hi  // Hi メッセージの送信
  friend ! Bye // Byeメッセージの送信
}

Mainオブジェクトでfriendを作成し、メッセージを送っています。実行結果は以下のようになります。

Friend: hello
Friend: Bye

メッセージの送信にFriendが答えてくれました。


Mainクラスを以下のように変更した場合どのようになるでしょう。

object Main extends Application {
  val friend = new Friend
  friend ! Hi
  friend.start
  friend ! Hi
  friend ! Bye
}

startする前にHiメッセージを送信しています。実行結果は以下のようになります。

Friend: hello
Friend: hello
Friend: Bye

以下のようにすると実行結果としては何も表示されません。

object Example200 extends Application {
  val friend = new Friend
  friend ! Hi
  friend ! Bye
}

つまりHiというメッセージは送信され、キューに入れられ、friend.startによりメッセージの処理が開始されていることになります。

簡単な同期メッセージの送信と受信

上で見たメッセージの送信は非同期メッセージでした。つまり、friend ! Hi の呼出はブロックされません。これを少し詳しく見てみましょう。

import scala.actors.Actor
import scala.actors.Actor._

case object Hi
case object Bye

class Friend extends Actor {
  def act() {
    while(true) {
      receive {
        case Hi =>
          println("Friend: hello")
          Thread.sleep(1000)  // <---
          reply()             // <---
        case Bye => println("Friend: bye"); exit()
      }
    }
  }
}

object Main extends Application {
  val friend = new Friend
  friend.start
  println("Hi");  friend ! Hi
  println("Bye"); friend ! Bye
}

実行結果は以下のようになりました。

Hi
Bye
Friend: hello
Friend: bye

Mainオブジェクトを「friend ! Hi」→「friend !? Hi」に書き変えてみます。

object Main extends Application {
  val friend = new Friend
  friend.start
  println("Hi");  friend !? Hi
  println("Bye"); friend ! Bye
}

実行結果は以下のようになります。

Hi
Friend: hello
Bye
Friend: bye

「Friend: hello」を表示後、1秒ほどして「Bye」が表示されました。これは「friend !? Hi」が同期メッセージの送信となり、処理がブロックされたことを意味します。(ちなみにreply()を記述しない場合には、「friend !? Hi」のメッセージ送信が永遠にブロックされ続けます)


ここでは簡単にActorライブラリの使い方を見てみました。
次回はもう少し詳しく見ていきたいと思います。