10. STMを使ったコード
(def counter (ref 42))
counter
42
Thread A Thread B
(dosync (dosync
(let [v @counter] (let [v @counter]
(when (<= v 100) (when (<= v 100)
(ref-set counter (ref-set counter
(inc v))))) (inc v)))))
11. STMを使ったコード
(def counter (ref 42))
counter
42
Thread A Thread B
(dosync (dosync
(let [v @counter] (let [v @counter]
(when (<= v 100) (when (<= v 100)
(ref-set counter (ref-set counter
(inc v))))) (inc v)))))
12. STMを使ったコード
(def counter (ref 42))
counter
42
Thread A Thread B
(dosync (dosync
(let [v @counter] (let [v @counter]
(when (<= v 100) (when (<= v 100)
(ref-set counter (ref-set counter
(inc v))))) (inc v)))))
42
13. STMを使ったコード
(def counter (ref 42))
counter
42
Thread A Thread B
(dosync (dosync
(let [v @counter] (let [v @counter]
(when (<= v 100) (when (<= v 100)
(ref-set counter (ref-set counter
(inc v))))) (inc v)))))
42 42
14. STMを使ったコード
(def counter (ref 42))
counter
42
Thread A Thread B
(dosync (dosync
(let [v @counter] (let [v @counter]
(when (<= v 100) (when (<= v 100)
(ref-set counter (ref-set counter
(inc v))))) (inc v)))))
43 42
15. STMを使ったコード
(def counter (ref 42))
counter
42
Thread A Thread B
(dosync (dosync
(let [v @counter] (let [v @counter]
(when (<= v 100) (when (<= v 100)
(ref-set counter (ref-set counter
(inc v))))) (inc v)))))
43 この時点の変更はBからは見えない
42
16. STMを使ったコード
(def counter (ref 42))
counter
42
Thread A Thread B
(dosync (dosync
(let [v @counter] (let [v @counter]
(when (<= v 100) (when (<= v 100)
(ref-set counter (ref-set counter
(inc v))))) (inc v)))))
43 42
17. STMを使ったコード
(def counter (ref 42))
counter
42
Thread A Thread B
(dosync (dosync
(let [v @counter] (let [v @counter]
(when (<= v 100) (when (<= v 100)
(ref-set counter (ref-set counter
(inc v))))) (inc v)))))
43 他で値が変更されていなければコミット
42
18. STMを使ったコード
(def counter (ref 42))
counter
43
Thread A Thread B
(dosync (dosync
(let [v @counter] (let [v @counter]
(when (<= v 100) (when (<= v 100)
(ref-set counter (ref-set counter
(inc v))))) (inc v)))))
43 コミット! 42
19. STMを使ったコード
(def counter (ref 42))
counter
43
Thread A Thread B
(dosync (dosync
(let [v @counter] (let [v @counter]
(when (<= v 100) (when (<= v 100)
(ref-set counter (ref-set counter
(inc v))))) (inc v)))))
42
20. STMを使ったコード
(def counter (ref 42))
counter
43
Thread A Thread B
(dosync (dosync
(let [v @counter] (let [v @counter]
(when (<= v 100) (when (<= v 100)
(ref-set counter (ref-set counter
(inc v))))) (inc v)))))
43
21. STMを使ったコード
(def counter (ref 42))
counter
43
Thread A Thread B
(dosync (dosync
(let [v @counter] (let [v @counter]
(when (<= v 100) (when (<= v 100)
(ref-set counter (ref-set counter
(inc v))))) (inc v)))))
43
22. STMを使ったコード
(def counter (ref 42))
counter
43
Thread A Thread B
(dosync (dosync
(let [v @counter] (let [v @counter]
(when (<= v 100) (when (<= v 100)
(ref-set counter (ref-set counter
(inc v))))) (inc v)))))
Aが値を変更したので失敗 43
23. STMを使ったコード
(def counter (ref 42))
counter
43
Thread A Thread B
(dosync (dosync
(let [v @counter] (let [v @counter]
(when (<= v 100) (when (<= v 100)
(ref-set counter (ref-set counter
(inc v))))) (inc v)))))
トランザクションを最初からやり直す 43
24. STMを使ったコード
(def counter (ref 42))
counter
43
Thread A Thread B
(dosync (dosync
(let [v @counter] (let [v @counter]
(when (<= v 100) (when (<= v 100)
(ref-set counter (ref-set counter
(inc v))))) (inc v)))))
43
25. STMを使ったコード
(def counter (ref 42))
counter
43
Thread A Thread B
(dosync (dosync
(let [v @counter] (let [v @counter]
(when (<= v 100) (when (<= v 100)
(ref-set counter (ref-set counter
(inc v))))) (inc v)))))
43
26. STMを使ったコード
(def counter (ref 42))
counter
43
Thread A Thread B
(dosync (dosync
(let [v @counter] (let [v @counter]
(when (<= v 100) (when (<= v 100)
(ref-set counter (ref-set counter
(inc v))))) (inc v)))))
44
27. STMを使ったコード
(def counter (ref 42))
counter
43
Thread A Thread B
(dosync (dosync
(let [v @counter] (let [v @counter]
(when (<= v 100) (when (<= v 100)
(ref-set counter (ref-set counter
(inc v))))) (inc v)))))
44
28. STMを使ったコード
(def counter (ref 42))
counter
44
Thread A Thread B
(dosync (dosync
(let [v @counter] (let [v @counter]
(when (<= v 100) (when (<= v 100)
(ref-set counter (ref-set counter
(inc v))))) (inc v)))))
コミット! 44
29. ClojureのSTM観
Thread A Thread B
a
... @a ...
... (ref-set a ...) ...
... (ref-set b ...) ...
b
... (ref-set b ...) ...
... (ref-set c ...) ... c
トランザクションは更新するRefを集めていく
途中で他のトランザクションが手を出しているRefに触ったらアボート
→リトライ
すべてのRefを集めて最後まで行ければゴール→コミット
30. ClojureのSTM観
Thread A Thread B
a
... @a ...
... (ref-set a ...) ...
... (ref-set b ...) ...
b
... (ref-set b ...) ...
... (ref-set c ...) ... c
トランザクションは更新するRefを集めていく
途中で他のトランザクションが手を出しているRefに触ったらアボート
→リトライ
すべてのRefを集めて最後まで行ければゴール→コミット
writeが多いとリトライが頻発して性能低下
36. write skew
MVCCで起こる現象
複数のトランザクション間で不変条件を破るような変更が行
われたときに発生
不変条件
@a + @b <= 3
Thread A Thread B
(dosync (dosync
(when (<= (+ @a @b) 2) (when (<= (+ @a @b) 2)
(ref-set a (inc a)))) (ref-set b (inc b))))
37. write skew
MVCCで起こる現象
複数のトランザクション間で不変条件を破るような変更が行
われたときに発生
不変条件
@a + @b <= 3
Thread A Thread B
(dosync (dosync
(when (<= (+ @a @b) 2) (when (<= (+ @a @b) 2)
(ref-set a (inc a)))) (ref-set b (inc b))))
AとBで違うRefを変更しているので両者ともコミットに成功する
コミット後、不変条件は成り立たなくなる
38. ensure
write skewの問題は、暗に存在する「コミットする
まで変更されない」という条件が破られるために発
生する
Clojureでは (ensure <ref>) で、それ以降コミットが
完了するまで<ref>が変更されないことを保証する
Thread A Thread B
(dosync (dosync
(when (<= (+ @a @b) 2) (when (<= (+ @a @b) 2)
(ensure b) (ensure a)
(ref-set a (inc a)))) (ref-set b (inc b))))
ensureしているRefが他方に変更されればリトライ
39. Contention management
Thread A Thread B
a
... @a ...
... (ref-set a ...) ...
... (ref-set b ...) ...
b
... (ref-set b ...) ...
... (ref-set c ...) ... c
40. Contention management
Thread A Thread B
a
... @a ...
... (ref-set a ...) ...
... (ref-set b ...) ...
b
... (ref-set b ...) ...
... (ref-set c ...) ... c
2つのトランザクションが同じRefをつかもうとしたとき、どちら
を生かし、どちらをアボートするか?
41. Contention management
Thread A Thread B
a
... @a ...
... (ref-set a ...) ...
... (ref-set b ...) ...
b
... (ref-set b ...) ...
... (ref-set c ...) ... c
2つのトランザクションが同じRefをつかもうとしたとき、どちら
を生かし、どちらをアボートするか?
戦略次第で性能が大きく左右される
49. 参考文献
M. Herlihy and N. Shavit. “The Art of Multiprocessor Programming,
Revised Reprint.” Morgan Kaufmann Publishers Inc. 2012
M. Fogus and C. Houser, “The Joy of Clojure.” Manning Pubns Co.
2011
Nielsen, Peder RL, and Patrick T. Kristiansen. "Benchmarking
Contention Management Strategies in Clojure’s Software." Artificial
Intelligence 8.3 (1977): 323-364.
R. Mark Volkmann. “Software Transactional Memory.” http://
java.ociweb.com/mark/stm/article.html