Blog
【Akka入門の入門】Part.2 アクター子アクター孫アクター
新卒の増田です(^o^)
前回に引き続きAkkaの超基礎的な事についてコードを交えて説明していきます!
(前回は顔文字多すぎ…みたいな声もあったので今回から少なめにしますw)
前回はメッセージを送っただけでした。
アクターには「どのメッセージを受け取ったら何をするか」を定義して、メッセージを送ることによって非同期にアクターを操作し並列処理を行います。
アクターにメッセージを送る時、アクターを参照しているインスタンス(ActorRefインスタンス)を使いました。
1 |
val actor = system.actorOf(Props[HelloActor]) |
ですが、なんとこれを使わなくてもメッセージを送る方法があります!
全てのアクターはアドレスを持っていて、アクターが生成された時に
1 2 3 4 5 6 7 8 9 10 11 |
$ sbt > console scala> import akka.actor.{ActorSystem,Props} import akka.actor.{ActorSystem, Props} scala> val system = ActorSystem("mySystem") system: akka.actor.ActorSystem = akka://mySystem scala> val myActor = system.actorOf(Props[HelloActor]) myActor: akka.actor.ActorRef = Actor[akka://mySystem/user/$a#486500662] |
このようにアドレスが割り当てられます!
akka://mySystem/user/$a#486500662
前回作ったプロジェクト上でsbt consoleコマンドを使うと、そのプロジェクト内で書いたクラスが対話形式で使えます、便利ですね〜(^o^)
ちなみにアクターを生成する時に名前を付けると
1 2 |
scala> val myActorWithName = system.actorOf(Props[HelloActor],"masuda'sActor") myActorWithName: akka.actor.ActorRef = Actor[akka://mySystem/user/masuda'sActor#-1513573312] |
アドレスにさっき付けた名前が入っています(^o^)
akka://mySystem/user/masuda’sActor#-1513573312
このアドレスを知っていればメッセージを送ることができます。
ところで、URLやファイルパスと同じ階層構造になっていますよね?
実はActorSystem全体がヒエラルキー構造になっていて、アクターが子アクターを作る事ができます。
実際に例を見ないと分かりにくいので、親子アクターを作ってみましょう!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import akka.actor.{Actor,Props} case class ForChild(msg: String) case class Child() class ChildActor extends Actor{ def receive = { case msg:String => println("(Child): " + msg) } } class SupervisorActor extends Actor{ override def preStart = { context.actorOf(Props[ChildActor],"childActor") } def receive = { case msg:String => println("(Supervisor): " + msg) case ForChild(msg:String) => context.actorFor("childActor") ! msg case Child => sender ! context.actorFor("childActor") } } |
「親アクターは子を監視する」という意味で、親アクターの事を今後はSupervisorと呼びます…!
それぞれのアクターにreceiveメソッドを定義したのは前回と同じです。
ChildActorはStringのメッセージが来たらprintlnして
SupervisorActorはStringのメッセージならprintln、ForChild型ならchildActorに中のStringを送ります。
Child型なら送信元にchildActorのActorRefを送ります。
今回はSupervisorActorのpreStartメソッド内で、childActorを生成しています!
preStartはアクターが起動する前に実行されるメソッドで、他にもpostStop・preRestart・postRestartがあります。
ではSupervisorActorにメッセージを送りましょう
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$ sbt > console scala> import akka.actor.{ActorSystem,Props} import akka.actor.{ActorSystem, Props} scala> val system = ActorSystem("mySystem") system: akka.actor.ActorSystem = akka://mySystem scala> val superActor = system.actorOf(Props[SupervisorActor],"supervisorActor") superActor: akka.actor.ActorRef = Actor[akka://mySystem/user/supervisorActor#316238034] scala> superActor ! "Hello" (Supervisor): Hello scala> superActor ! ForChild("Hello") (Child): Hello |
Supervisorに送ったメッセージがChildに送られています!
ちなみにChildというメッセージを送信して、childActorのActorRefを取得すると…
1 2 3 4 5 6 7 |
scala> val reply = superActor ? Child reply: scala.concurrent.Future[Any] = scala.concurrent.impl.Promise$DefaultPromise@4fbab42b scala> reply.onSuccess{ | case actor:ActorRef => println(actor.toString) | } Actor[akka://mySystem/user/supervisorActor/childActor#5272165] |
(askのためのimportやimplicitなど前回やった諸々は省略…)
childActorのアドレスがakka://mySystem/user/supervisorActor/childActorになっていて、supervisorActorの下の階層になっています!!
ActorSystem全体がヒエラルキーになっていて、自分で作ったアクターはそのトップのアクターの子アクターになってます。
(supervisorActorはmySystemのrootアクターの子アクターのuserアクターの子アクターということになります。)
↑Akkaのドキュメント参照↑
それで…?
って感じでしょうか(´-ω-`)
でも、このヒエラルキー構造がAkkaの耐障害性UPに重要な役割を果たしているのです!!
…詳細は次回(^o^)!!
(↓その重要な役割が完全にネタバレになっちゃいますが、私が勉強した事をまとめたスライドその②です↓)
[slideshare id=43156248&doc=devakka4-5-150102143643-conversion-gate01]
Author