Your SlideShare is downloading. ×
ClojureではじめるSTM入門
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

ClojureではじめるSTM入門

6,300
views

Published on

Published in: Technology

0 Comments
18 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
6,300
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
18
Comments
0
Likes
18
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. ClojureではじめるSTM入門 @athos0220 並列/並行基礎勉強会
  • 2. 自己紹介@athos0220趣味でClojure触ってます正直STMとかまともに使ったことないわー付け焼刃に勉強したので間違ってるところあるかも(´・ω・`)→生温かくご指摘お願いします
  • 3. What’s STM?
  • 4. STMとはSoftware Transactional Memoryソフトウェアトランザクショナルメモリは、データベーストランザクションに似た並行性制御機構であり、並列計算を行う際の共有メモリへのアクセス法である。この機構はロックベースの同期を用いた並行性制御の代替手段として機能し、ノンブロッキングな方法で実装される物もある。 Wikipediaより楽観的: 他のスレッドを気にせずとりあえず実行してみる 変なことになったらリトライする最近盛んに研究されている(らしい)
  • 5. ロックの利点と欠点利点 いつロックを取得し、解除するかを陽に制御できる 開発者にとって馴染みがある方法 多くのプログラミング言語でサポートされている欠点 ロックのとる順序によってデッドロックが起こる 優先度逆転が起こる composableでない
  • 6. STMの利点と欠点利点 デッドロックや優先度逆転が起きない 楽観的なので並行性が向上する composableである(ネストできる)欠点 リトライが頻発することでパフォーマンスが悪くなる 余分なオーバーヘッドがかかる トランザクション内では副作用を避ける必要がある
  • 7. 各言語での対応状況言語(処理系)組込み Clojure, Haskell, Perl6(Pugs)ライブラリ C, C++, C#, Common Lisp, Java, OCaml, Python, Scala, Smalltalkどの入門書にもSTMの解説があるのはClojureだけ
  • 8. How to use STM in Clojure
  • 9. STMの基本構文・関数(dosync <body>):<body>をトランザクションで実行(ref <val>):トランザクション内で変更が可能な参照(Ref型)を生成(deref <ref>):Refにくるまれた値をデリファレンス。@<ref>は糖衣構文(ref-set <ref> <val>):Refの値を変更する。dosyncの外で使うとエラーになる
  • 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が多いとリトライが頻発して性能低下
  • 31. Under the hood of STM
  • 32. Version Clockすべてのトランザクションで共有するクロックトランザクションの開始やリトライ、コミットのたびにインクリメントされる各トランザクションは自分が開始されたときのクロックの値を記録するコミット時にはそのときのクロックの値をRefに記録する
  • 33. RefいわゆるAtomic Object主に以下で構成されている 値の履歴をもつリングバッファ ref-setしたが未コミットのトランザクション Refを参照・更新する際に使われるロック
  • 34. in-transaction valuesトランザクション内でアクセスしたRefとその値をローカルに記録する Refを更新するときはローカルな値を更新する Refから値を読み出すとき、 ローカルな値があればそれを読み出す なければ、Refの履歴をたどってトランザ クション開始以前の値を読み出す
  • 35. MVCC多版型同時実行制御 (Multiversion Concurrency Control) トランザクションの実行中、他のトランザクションが既に 更新した値を読み出すと一貫性がなくなる これを防ぐには以下のような方法がある(2つめがMVCC) 他が更新済みの値を読み出そうとした時点でアボート してリトライ 値の履歴をとっておいて、トランザクション開始時ま で って値を読み出す 1つめの方法はリトライの可能性が高くなる
  • 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をつかもうとしたとき、どちら を生かし、どちらをアボートするか? 戦略次第で性能が大きく左右される
  • 42. Contention managementの戦略
  • 43. Contention managementの戦略 Agressive: 相手を殺す
  • 44. Contention managementの戦略 Agressive: 相手を殺す Polite: 自分が死ぬ
  • 45. Contention managementの戦略 Agressive: 相手を殺す Polite: 自分が死ぬ Karma: あまり仕事をしていない方が死ぬ
  • 46. Contention managementの戦略 Agressive: 相手を殺す Polite: 自分が死ぬ Karma: あまり仕事をしていない方が死ぬ Priority: 年功序列。若いやつが死ぬ
  • 47. Contention managementの戦略 Agressive: 相手を殺す Polite: 自分が死ぬ Karma: あまり仕事をしていない方が死ぬ Priority: 年功序列。若いやつが死ぬClojureのContention managementはPriority+α
  • 48. まとめロックを使って同期するのは辛いSTM!STM! Clojureなら初心者でもSTM使えますただし、writeが多いと性能低下するなど、問題点もある → 銀の弾丸ではないしかし、将来的にはGCのように適用範囲は広がっていくのでは…?
  • 49. 参考文献M. Herlihy and N. Shavit. “The Art of Multiprocessor Programming,Revised Reprint.” Morgan Kaufmann Publishers Inc. 2012M. Fogus and C. Houser, “The Joy of Clojure.” Manning Pubns Co.2011Nielsen, Peder RL, and Patrick T. Kristiansen. "BenchmarkingContention Management Strategies in Clojure’s Software." ArtificialIntelligence 8.3 (1977): 323-364.R. Mark Volkmann. “Software Transactional Memory.” http://java.ociweb.com/mark/stm/article.html