ついに アクター について語る時がきました。
Scalaの醍醐味の一つです。
そして難しいです。。。
でも、アクターを使うと並列処理を扱うことが簡単になります。
ただアクターには色々な種類があるので、そこが簡単じゃないかも。。。
アクターの歴史
2.9のアクターは知らないんだけど、2.10からは標準のscala.actor
パッケージが非推奨になっていて
今後削除されるみたいなんだ。
そして、今後はAkkaのアクターを使うことが推奨されている。
Akkaとは
Typesafe社が開発していて、高い抽象度・並行・スケーラブルなアプリケーションを実装するためのScala・Javaのイベント駆動の分散並列型アプリケーションフレームワークです。
Typesafe社は、Scalaの生みの親Martin Oderskyの会社ですね。
アクターとは
ところで アクター とは何でしょうか?
__アクターモデル__というものがあるので、Wikipediaの定義を見てみましょう。
アクターモデル(英: actor model)とは、1973年、カール・ヒューイット、Peter Bishop、Richard Steiger が発表した並行計算の数学的モデルの一種[1]。アクターモデルでは、並行デジタル計算の汎用的基本要素として「アクター」という概念を導入している。アクターモデルは並行性の理論的理解のフレームワークとして使われるほか、並行システムの実装の理論的基礎としても利用されてきた。
そして続き。
アクターモデルの基本は「全てのものはアクターである」という哲学である。これはオブジェクト指向プログラミングにおける「全てのものはオブジェクトである」という考え方と似ているが、オブジェクト指向ソフトウェアでは基本的に逐次的に実行するのに対して、アクターモデルでは本質的に並行性を備えている点が異なる。アクターは並行的に受信するメッセージに対応した以下のような振る舞いを備えた計算実体(Computational Entity)である:
・(他の)アクターに有限個のメッセージを送信する。
・有限個の新たなアクターを生成する。
・次に受信するメッセージに対する動作を指定する。
こんなものがアクターモデルです。わかりやすいですね。
僕の理解では下記な感じとなりました。
- オブジェクトである。そしてオブジェクト指向とそんなに変わらない。
- 並行性を備える。これがオブジェクト指向との最大の違い。
そして別のサイトで見つけた、アクター自身の説明。
「アクター」実装は要するに、アクターと呼ばれる実行エンティティー同士でのメッセージ交換を利用して作業の調整を行う方法です (「プロセス」、「スレッド」、「マシン」といった言葉を意図的に避けていることに注意してください)。
実行エンティティというのは、実体は色々とあるという話だと思います。
Javaのスレッドより簡単にconcurrentを実現できるっていう話を良く聞くと、 実体はスレッド間のやり取り のイメージを持ってしまう。だけど、スレッドという単位で決まっているわけではないし、 プロセス 、 マシン という単位で決まっているわけでもない。
なので実体はいくつかあって、それ抽象化した概念が 実行エンティティ ってとこですかね。
メッセージ
エンティティ間を繋ぐもの。
オブジェクト指向でも、オブジェクト間を繋ぐのはメッセージですね。
とは言え、エンティティは直接メッセージをやりとりしているわけではありません。
メールボックス経由でメッセージのやりとりを行っています。
メールボックス
メッセージを入れておく箱。アクターが持っています。
定義みたいの書いてみたけど
やっぱりスレッド間通信が簡単にできるというイメージが、最初はわかりやすいと思う。
イメージ
最後に絵を描いてみたぞ。最小構成だから寂しいことになっているぞ。
クラス図ぽくしているから。
Client
は、アクターにメッセージを送信する側だ。
Actor
は、今まで出てきたアクターだ。
message
でやりとりするんだ。
アクターを使う
早速ソースコードを書いてみよう!
今回はakka-actor_2.10-2.2.3.jar
を使ってみます。
プロジェクトの設定
どういうやり方にしようか迷ったんですけど、Gradleで実行する体で記述していきます。
sbt使っている人は、自分で設定してね!
Gradleのインストール
まず、Gradleのインストールから。
Gradleのインストールはこちらを参考にして下さい。
プロジェクト作成
次に、プロジェクト作成なんだけど、今回のソースコードはいつものgistじゃなくてリポジトリを作ったよ。
以下でcloneしてね。
$ git clone https://github.com/f81/actor_sample.git
構成は以下な感じとなっています。
actor_sample $ tree
.
├── LICENSE
├── README.md
├── build
├── build.gradle
└── src
├── main
│ ├── resources
│ └── scala
│ └── ActorSample.scala
└── test
├── resources
└── scala
ソースコード
準備が色々大変だったけど、ようやくソースコードだ。
import akka.actor.ActorSystem
import akka.actor.Props
import akka.actor.Actor
import akka.routing.RoundRobinRouter
object ActorSample {
def main(args: Array[String]): Unit = {
val system = ActorSystem("helloSystem")
val router = system.actorOf(Props[HelloActor].withRouter(RoundRobinRouter(4)))
router ! "Hello"
system.shutdown
}
}
class HelloActor extends Actor {
def receive = {
case "Hello" => println("Hello World!!")
case _ => println("Bad World!!")
}
}
Gradleで実行!
ソースコードを説明するよりも、とりあえず動かしちゃおう!
$ cd actor_sample
$ gradle run
:compileJava UP-TO-DATE
:compileScala
:processResources UP-TO-DATE
:classes
:run
Hello World!!
BUILD SUCCESSFUL
Total time: 11.639 secs
:run
のあとにでてきたHello World!!
が出力させたい結果だ!
説明
このソースでの登場人物は2人。ActorSampleオブジェクトとHelloActor。
先にアクターのHelloActorから。
HelloActor
akka.actor.Actor
を継承しています。
メッセージをreceive
で受け取ると、メッセージが何であるかを判断し、何かをします。
ここでは以下のようにしています。
- メッセージで文字列
Hello
を受け取った場合は、Hello World!!
とコンソール出力 - メッセージで文字列
Hello
以外を受け取った場合は、Bad World!!
とコンソール出力
かなり簡素に用意しましたが、これがアクターです。
ActorSample
今回の実行時のメインクラスとなります。
ここでやりたいことは、アクターにメッセージを送ることです。その箇所は
router ! "Hello"
となります。
ここのrouter
は、その前で定義しています。
val system = ActorSystem("helloSystem")
val router = system.actorOf(Props[HelloActor].withRouter(RoundRobinRouter(4)))
ActorSystem
は、アクター全体を管理するコンテナオブジェクトのようなモノだと今回は説明させてください。
こいつをsysytem
という名前にしています。
そしてsystem
から、HelloActor
インスタンスを管理するrouter
を取得します。
僕はrouter
を、オブジェクトプールと捉えています。
今回はRoundRobin
としてrouter
を用意していますが、他にも種類があります。
HelloActor
と、router
の出どこはわかったかな?
HelloActor
のrouter
にメッセージを渡すと、HelloActor
が動くんだ。
そしてメッセージを渡すと着に使うのが!
です。
!
はもちろんメソッドです。
更に、アクターの戻り値を必要としないことも言っています。
アクターの戻り値を必要とする場合は?それはまた別の機会にします。
これでakkaのアクターの一番最初のところ見ることができたかな?
まとめ
Javaでスレッドを扱うのと較べてスッキリ書ける印象を持てたね。
今回はアクターの初歩のところを語ってみた。
Akkaはフレームワークというくらいに大きなモノなので、見切れていないし今回ほとんど語れていないです。
進化が止まらないAkkaをもっと使ってみようぜ!
次回からについて
本20章をもって、「やってみよう Scala!基礎編」は終了です。
読んでいただいた方、コメントをいただいた方、ストックしていただいた方、
皆様ありがとうございました!
それでは、さようなら。富林寺先生の次回作にご期待ください!
という打ち切り宣言ではなく、
続けて次回から「やってみよう Scala!応用編」をはじめます。
Scala関連日本語情報の充実に微力ながら貢献できるよう、引き続き投稿を続けますのでよろしくお願いいたします!