S-JIS[2011-02-26] 変更履歴
|
|
Actorは、送られてきたメッセージ(オブジェクト)に対して処理を行う。
1つのActorに対して1つのスレッドが割り当てられる。
同一Actorに複数のメッセージが送られた場合、キュー(メッセージボックス)に入れられ、そこから順番に処理していく。
Actor同士は同じデータを共有することが無い為、スレッド間の競合を気にする必要が無い。
ただしメッセージとして送られたオブジェクトは共有されうるので、同一オブジェクトを複数Actorに送るような事をする場合には注意が必要。
ただ、オブジェクトが不変であれば気にする必要は無いので、不変オブジェクトが推奨されるのだろう。
普通は直接Actorトレイトを使うことは無いが、基本(実際に使用される動作)として。
| Scala | Java相当 | 備考 |
|---|---|---|
import scala.actors.Actor |
||
class Sample extends Actor { def act() = { 〜 } } |
class Sample extends Thread { @Override public void run() { 〜 } } |
Actorのact()メソッドがThreadのrun()メソッドに相当する。 act()内でループしない限り、一度だけ実行して終了する。 |
val s = new Sample s.start |
Sample s = new Sample(); s.start(); |
startでスレッド実行を開始する。 |
s.restart |
restartで一度終了したActorを再実行できる。 | |
class Sample extends Actor { def act() = { loop { react { case "end" => exit case m => println(m) } } } } val s = new Sample s.start s ! "hello" //メッセージ送信 |
メッセージを受け取る記述。 receiveやreactはメッセージを受け取るまで待機する。 「!」メソッドでメッセージを送信する。 |
Actorを扱う為のメソッドはActorオブジェクト(コンパニオンオブジェクト)にも定義されている。
import scala.actors.Actor._
| メソッド | 例 | 実際のイメージ | 備考 |
|---|---|---|---|
| actor |
val a = actor {
println("hello")
}
|
val a = new Actor { def act() = { println("hello") } } a.start |
actorメソッドで処理内容を書くと、自動的にスレッドがstartする。 |
| loop |
val a = actor {
loop {
〜
}
}
|
while(true) {
〜
}
|
act()内は一度実行されると終了するので、何度も処理する為にループする必要がある。 素直にwhile式を使えばいいような気がするのだが、actorではloopというメソッドが用意されている。 loopは無限ループなので、ループ内で何らかの条件によって終了するように作らないといけない。 |
| loopWhile |
val a = actor {
loopWhile(条件) {
〜
}
}
|
while(条件) {
〜
}
|
loopは無限ループだが、loopWhileでは(while式の様に)ループ条件演算を指定できる。 |
| receive |
val a = actor {
loop {
receive {
case "end" => exit
case m => println(m)
}
}
}
|
receiveでメッセージを受け取る。 receiveはメッセージが来るまで待機する。 受け取ったメッセージを(match式の様に)場合分けして処理を行う。 パターンにマッチしないメッセージがある場合はMatchErrorとはならず、メッセージボックス(キュー)に残り続ける。 (reactの方がスレッドの処理効率がいいらしい。関数脳p.284) |
|
| react |
val a = actor {
loop {
react {
case "end" => exit
case m => println(m)
}
}
}
|
メッセージを受け取る。receiveより効率がいいらしい。 | |
val a = actor {
loop {
{
react {
case "end" => exit
case m => println(m)
}: Unit
} andThen {
println("after")
}
}
}
|
reactは戻り値を返さない(戻り型がNothingである)ので、reactブロックの後に処理を書いても実行されない。 andThenを使うとreactの後で実行する処理を記述できる。 ただしandThenはNothingのメソッドではないので(「react{ 〜 } andThen { 〜 }」のような書き方が出来ない)、Unitに変換する必要がある。 (参考: 制御構造) |
||
| reactWithin |
val a = actor {
import scala.actors.TIMEOUT
loop {
reactWithin(5*1000) {
case TIMEOUT =>
println("end")
exit
case m =>
println(m)
}
}
} |
タイムアウトありのreact。 指定時間の間にメッセージが来ないと、TIMEOUTオブジェクトがメッセージとして送られてくる。 |
|
| reply |
val a = actor {
loop {
react {
case "end" => exit
case n:Int => reply(n*2)
case m => println(m)
}
}
}
|
メッセージの送信元に返信を返す。 (送信元が返信を受け取る為には、!?か!!メソッドを使ってメッセージを送信する) |
|
| exit |
val a = actor {
loop {
react {
case "end" => exit
case m => println(m)
}
}
}
|
exitでアクター処理を終了する。 | |
| ! |
a ! "メッセージ" |
アクターにメッセージを送信するには「!」メソッドを使う。 メッセージはオブジェクトであれば何でもいい。 アクターがreplyで返信を返したとしても無視する。 |
|
| !? |
val r = a !? "メッセージ" |
アクターにメッセージを送信し、返信(reply)を受け取る。 返信が返ってくるまでブロックする(待機する)。 |
|
| !! |
val f = a !! "メッセージ" val r = f() |
アクターにメッセージを送信し、返信を受け取る為のFutureオブジェクトを返す。 Futureのapply()メソッドを呼べば返信が取得できる。 apply()メソッドは、返信が返ってくるまでブロックする(待機する)。 メッセージを送信してから返信が返ってくるまでに別の処理を行いたい場合に使用する。 |
|
| mailboxSize |
val a = actor {
loop {
react {
case "end" => exit
case 'm =>
println(mailboxSize)
case n:Int =>
println(n)
}
}
}
|
mailboxSizeでメールボックス(キュー)に入っているメッセージの個数を取得できる。 (処理されなかったメッセージはメールボックスに残り続ける) |
|
| getState |
a.getState |
アクターの稼動状態を取得する。 |