More Related Content Similar to Actor&stm (20) Actor&stm6. Q1.スレッドを止められるか...
public class StopThread implements Runnable {
private boolean terminate;
public void run() {
while (! terminate) {
// なにかの処理
}
}
public void setTerminate(boolean terminate) {
this. terminate = terminate;
}
}
11. メモリモデルはスレッド単位
スレッドA terminate ← true terminate(true)
スレッドB false ← terminate terminate(false)
12. メモリモデルはスレッド単位
スレッドA terminate ← true terminate(true)
大域のterminate
スレッドB false ← terminate terminate(false)
13. メモリモデルはスレッド単位
スレッドA terminate ← true terminate(true)
同期化しないと
見えない 大域のterminate
スレッドB false ← terminate
true ← terminate terminate(false)
terminate(true)
15. volatileェ...
public class StopThread implements Runnable {
private volatile boolean terminate;
public void run() {
// (2) Volatile Load
while (! terminate) {
// スレッドで行う処理
}
}
public void setTerminate(boolean terminate) {
// (1) Volatile Store
this. terminate = terminate;
}
}
16. Q2.x,yの結果はどうなる?
x = 0; y = 0; a = 0; b = 0;
class AThread extend class BThread extend
Runnable { Runnable {
@Override @Override
public void run() { public void run() {
a = 1; b = 1;
x = b; y = a;
} }
} }
18. 何回目で発生したか (x , y)
004590 (1 , 1)
005606 (0 , 0)
045450 (0 , 1)
045451 (1 , 0)
105747 (0 , 0)
129356 (0 , 0)
26. メッセージを受信するActor
class MyActor extends Actor {
def act() = { // Runnable#run相当
loop { // while(true)の簡略表現
receive { // メッセージの待ち受け(ブロックする)
case "end" => exit
case msg: String => println(msg)
}
}
}
}
val myactor = new MyActor
myactor.start()
// 文字列を渡す
myactor ! “Hello”
// 終了メッセージを渡す
myactor ! “end”
27. 返事を返すActor
val myactor = actor {
loop {
receive {
case "end" => exit
case "Hello" => reply("World")
}
}
}
// 戻り値を取得(返事が戻るまでブロック)
val result = myactor !? “Hello”
28. Futureを返すActor
val myactor = actor {
loop {
receive {
case "end" => exit
case numbers: List[Int] =>
重いソート処理
reply(result)
}
}
}
// futureパターン
val future = myactor !! largeNumbers
while(!future.isSet){ Thread.sleep(1000) }
val result = future()
29. もっと簡潔に
val myactor = actor {
loop {
receive {
case "end" => exit
case msg: String => println(msg)
}
}
}
// 文字列を渡す(ブロックしない)
myactor ! “Hello”
// 終了メッセージを渡す (ブロックしない)
myactor ! “end”
30. reactはスレッドを節約する
val myactor = actor {
loop {
react {
case "end" => exit
case numbers: List[Int] =>
重いソート処理
reply(result)
}
// 制御を返さないので,ここは実行できない
}
}
31. リソースを共有しない利点
class MyActor extends Actor {
def act() = { // Runnable#run相当
loop { // while(true)の簡略表現
receive { // メッセージの待ち受け(ブロックする)
case "end" => exit
case msg: String => println(msg)
}
}
}
} シングルスレッド脳
val myactor = new MyActor
myactor.start() で考えればよい
// 文字列を渡す
myactor ! “Hello”
// 終了メッセージを渡す
myactor ! “end”
32. mutalbleなメッセージはやめよう
class Money(var amount:BigDecimal, val actorA = new MyActor
var currency: Currency) {
def plus(add: Money):Unit = { val actorB = new MyActor
var a = amount val money = new Money(10,
a = a + add.amount
amount = a Currency.getInstance("JPY"
} ))
// いろいろ省略
actorA ! ("set", money)
} actorB ! ("set", money)
class MyActor extends Actor { actorA ! ("add", money)
var money: Money = _ actorB ! ("add", money)
def act() = {
loop {
react {
case "end" => exit
case ("set", m) => money = m
case ("add", m) =>
money.plus(m)
}
}
}
}
33. mutalbleなメッセージはやめよう
class Money(var amount:BigDecimal, val actorA = new MyActor
var currency: Currency) {
def plus(add: Money):Unit = { val actorB = new MyActor
var a = amount val money = new Money(10,
a = a + add.amount
amount = a Currency.getInstance("JPY"
} ))
// いろいろ省略
amount 参照の可視性
actorA ! ("set", money)
} actorB ! ("set", money)
plusメソッドの原子性
class MyActor extends Actor { actorA ! ("add", money)
var money: Money = _ actorB ! ("add", money)
def act() = {
loop {
react {
case "end" => exit
case ("set", m) => money = m
case ("add", m) =>
money.plus(m)
}
}
}
}
35. スレッドセーフ?
class Sequence {
private var value = 0
def getValue = value
// ↓ スレッドセーフか?
def getAndIncrement() = {
value += 1 // Java だと value++
value
}
}
37. 0182 1998
0848 1998
3438 1998
3714 1998
3950 1998
40. ロックで同期化
class Sequence {
private var value = 0
def getValue = value
// ↓ ロックが必要
def getAndIncrement() = synchronized {
value += 1
value
}
}
41. STM(Ref)
class Sequence {
private var value = Ref(0)
def getValue = value.get
def getAndIncrement() = atomic {
value alter (_ + 1)
}
}
class Ref[T] ...
def alter(f: T T): T = {
val value = f(get)
set(value)
value
}
Editor's Notes \n \n \n \n \n \n 巻き上げ。最適化していいことになっているから、\n \n スレッドAで書き込んだら、次のスレッドBで読み込めるとは限らない。\n スレッドAで書き込んだら、次のスレッドBで読み込めるとは限らない。\n スレッドAで書き込んだら、次のスレッドBで読み込めるとは限らない。\n スレッドAで書き込んだら、次のスレッドBで読み込めるとは限らない。\n \n \n \n \n \n \n \n \n \n (1)のVolatile Storeの結果が(2)のVolatile Loadで見えることが保証される。volatileでなくてもAtomicBooleanでもよいですね。可変な変数はいろいろややこしい。\n 二つのスレッドが同時で動いたとしたら、x, yの結果はどうなりますか。\n 同期化したメモリアクセスではないので、スレッドのスケジューリング次第で運任せ。\n 結構な頻度でおこります。\n 理屈はこうです。スレッドAの命令がリオーダーされた場合は0,0となります。\n \n \n このように、そもそも人間のメンタルモデルから遠いノウハウを要求されてしまうのが、共有データ・ロックモデルです。ですから、本当にスレッドセーフで、スループットの出る マルチスレッドプログラミングができるプログラマは非常に少ないですし、これから目指すのも難しいということが言えます。\n \n 共有データロックモデルは簡単にデットロックを引き起こしてしまう可能性があるが、アクターは回避しやすい。これからは並行処理は、アクターから考えるべきです。\n メッセージパッシングによる抽象度の高い並行処理モデルが、アクターモデルです。アクターとしてはErlangが有名。アクターはスレッドとメールボックスが一体になったようなオブジェクトです。アクターに何かを依頼するときはメッセージを送信します。アクターで受信したメッセージはキューで管理され、キューから取り出されたメッセージに応じた処理が実行されます。\n リソースを共有しないので、シングルスレッドモデルでよいのです。\n \n \n actorという関数を引数に取るファクトリメソッド。\n receiveはブロックします。実行効率が悪い。もっと実行効率を上げるにはreactを使います。\n通常はアクターにはスレッドが割当てられます。 スレッドはたくさん作るとOutOfMemoryErrorを引き起こします。Javaで学んだようにスレッドをプーリングしてスレッドを再利用しなければなりません。reactはブロックせずに、スレッドを再利用します。ほとんどreceiveと同じことができますが、メッセージを処理しても制御を返しません。カレントスレッドは、次のアクターのために再利用されます。プログラム内のすべてのアクターがreactを使うなら1つのスレッド実行しようとします。ただし、コアの数によります。\n リソースを共有しないので、メッセージだけで通信していれば、シングルスレッドモデルでよいのです。\n しかし、落とし穴があってメッセージオブジェクトがmutableだとつらいことになります。とにかくImmutableにしないといろいろ面倒なことを考慮しないと、死にます。\n \n 同時複数のスレッドが同じ値を取得し、立て続けに加算した場合想定が崩れる。リードモディファイライトが、、\n 同時複数のスレッドが同じ値を取得し、立て続けに加算した場合想定が崩れる。リードモディファイライトが、、\n 結構な頻度でおこります。\n 同時複数のスレッドが同じ値を取得し、立て続けに加算した場合想定が崩れる。リードモディファイライトが、、\n \n 同時複数のスレッドが同じ値を取得し、立て続けに加算した場合想定が崩れる。リードモディファイライトが、、\n ロックを取得しないでアトミックな操作ができる。実行中のメモリIOを記録し、共有メモリに対しての変更を行う。\nロックがあればスレッド間の調停を行うが、この場合の整合性の検証は書き込み側ではなく、読み込み側に責任がある。トランザクション完了後に読み込み側で、他のスレッドで変更されていないかを検証させる。問題なければコミット、問題あればロールバックされてatomicの式は最初からやり直しになる。\n何がよいのかは、ロックコストを削減と、プログラムがわかりやすくなる。シングルスレッドで考慮すればいいか。デッドロック全く起きないか、トランザクションマネージャによって管理されているので安全です。\n\n