アクタモデルによるプログラミング
Scala でアクタ(scala.actor.Actor)を使ってプログラミングしていると、他のコンポーネントというかアクタに処理を依頼したあと、処理結果が帰ってくるまで待つような書き方をしなくなってくる。
一応、Actor では「!?」を使ってメッセージそ送信することで、相手の返信を待つようなことが出来るんだけど、相手が返信しなかったりすると、待ちっぱなしになってしまう。
あるメッセージは返信を期待し、他のメッセージは期待しないとかだと混乱するのもあってか、今のところメッセージの送信だけする「!」しか使ってない。
処理結果が必要な場合は以下みたいに、自身のアクタオブジェクトをメッセージに含めて、相手先からメッセージを送ってもらってる。
// メッセージ case class Register(sender: Actor, address: String) case class RegisterSuccess(address: String) case class RegisterFailure(address: String) // 登録依頼者のアクタ class ClientActor(registrar: Actor) extends Actor { def act(): Unit = { loop { reactWithin(1000) {// 1秒に1回登録しようとする case TIMEOUT => // 登録処理を依頼するだけ。完了まで待たない registrar ! Register(this, "foo@bar.baz") case RegisterSuccess(address) => // 登録成功 case RegisterFailure(address) => // 登録失敗 }} } } // 登録担当者のアクタ class RegistrarActor extends Actor { def act(): Unit = { loop { react { case Register(sender, address) => // 登録処理 val success = .....; if (success) sender ! RegisterSuccess(address) else sender ! RegisterFailure(address) }} } }
チュートリアルにあったオークションのサンプルも、たしかこんな風にやってた。
メッセージを非同期で対象性のあるものだと考えるとしっくりくる。
メッセージハブ的*1なアクタがいれば、メッセージにアクタを含める必要もない・・・けど、微妙に分かりづらくなりそう。
この書き方だと、他のアクタで処理が終わるのを待つことがないので、各アクタがちゃんと並列に実行される(と思う)。
ただ、メッセージのやり取りのみで協調動作させるため、複雑になってくると処理を理解しづらいかも。
*1:メッセージのブロードキャストとかするアクタ、アクタをグループ化&階層化するとか