Slide 1

Slide 1 text

go @xorphitus (2015-02)

Slide 2

Slide 2 text

この動物は並行処理が得意らしい

Slide 3

Slide 3 text

それを、こうじゃ ( )

Slide 4

Slide 4 text

S式 ( ) go

Slide 5

Slide 5 text

(let [ch (chan)] (go (while true (let [val (! ch “hello world”)))

Slide 6

Slide 6 text

go は大流行のようです

Slide 7

Slide 7 text

Go

Slide 8

Slide 8 text

今日は go な並行処理の 内側を少し覗いてみます

Slide 9

Slide 9 text

※ 書き方、使い方の話はしない

Slide 10

Slide 10 text

並行処理の俯瞰図(たぶん) 協調マルチタスク Python、Lua、あたりが主? ECMA6 でもやろうと思えば 共有メモリ ロック 例のあれ STM ClojureやらHaskellやら メッセージ パッシング アクター Scalaやら Erlangやら CSP/π計算 ベース Goやら Clojureのcore.asyncやら C# async やら

Slide 11

Slide 11 text

Go の並行処理 (goroutine) CSP (Communicating Sequential Processes) および π計算 (pi-calculus) の2つを混ぜて作った並行処理、らしい チャネル渡しの概念はπ計算のもの、らしい

Slide 12

Slide 12 text

CSP と π計算 どちらもプロセス代数の一種 プロセス代数っていうのは ● 並行システムを代数で表現したもの ● メッセージパッシング ● 代数式を解くことで並行処理の恒等的性質を明 らかにする、らしい ○ これ、デッドロックするんじゃね?とか

Slide 13

Slide 13 text

CSP 自販機の例 自販機はコインを入れてジュースが出て止まる VendingMachne = coin -> juice -> STOP 人間はコインまたはカードでの支払いを選択し、止まる Person = (coin -> STOP)□(card -> STOP) 自販機と人間を並列化すると VendingMachine|[{coin, card}]|Person ≡ coin -> juice -> STOP 上記を何やかんやすると、自販機・人間の並列プロセスから (juice -> STOP)□STOP ジュースを出して止まる、または単に止まる、非決定性プロセスが得られる

Slide 14

Slide 14 text

「らしい」

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

商業プログラマから見た goroutine 自分のような商業プログラマには とにかく軽量なスレッド として有り難く使わせてもらえれば十分 背後の計算機科学的理論は、2分で挫折

Slide 17

Slide 17 text

まさに商業プログラマ!!

Slide 18

Slide 18 text

ところで 軽量スレッドって 何だろう?

Slide 19

Slide 19 text

軽量スレッド/文法的なところは ● メッセージパッシングにより ○ レースコンディションの回避 ○ ロックをとってほげほげ、の回避 ● メッセージの授受や sleep 等のイベント処理 が、call back hell なしに書ける

Slide 20

Slide 20 text

軽量スレッド/もう少し低レイヤ ● OSのスレッドよりも更に軽い ● 一度に立ち上げられる数がたくさん ● コンテキストスイッチのコストが低い ● 単一のスレッド内でも複数起動し得る ● ファイバはこれに近いっちゃ近いけど軽量スレッ ドはプリエンプティブ(に見える) ● アクターも同じノリだろうか?

Slide 21

Slide 21 text

何これ どうやって動いてんの?

Slide 22

Slide 22 text

Go のアプローチ goroutine とは 「スレッドによって多重化されたコルーチン」 らしい 次スライドにイメージ図を描いてみた 参考 http://golang.org/doc/faq#goroutines http://stackoverflow.com/questions/24599645/

Slide 23

Slide 23 text

goroutine のイメージ(たぶん) coroutine 0 thread 0 coroutine 1 blocking thread 1 coroutine 1 scheduler call call yield 待機状態の coroutineを 移動! 別スレッドにて coroutine 0 を 待たずに続行

Slide 24

Slide 24 text

goroutine マルチコア対応 環境変数 GOMAXPROCS を変更する この値に応じて実スレッドを起動し goroutine の処理を分散して割り当てる デフォルトは 1

Slide 25

Slide 25 text

Clojure のアプローチ go はというのはマクロで 中身を停止・再開可能なステートマシンに 変換して 他のタスクにブロックされている間は止める 参考 http://clojure.com/blog/2013/06/28/clojure-core-async-channels.html http://endot.org/notes/2014-02-14-core-async-clojure/

Slide 26

Slide 26 text

go (Clojure) のイメージ (go (...) (...)) macro expansion (go (...) (...)) macro expansion thread task 0 task 1 チャネルへの 入力待ち チャネルに 入力 IOC スレッドと言う

Slide 27

Slide 27 text

go (Clojure) のイメージ thread チャネルへの 入力待ち チャネルに 入力 state 待ちになったら state を他所で維持しつつ スレッド上の処理から 除外する チャネルへの入力が あったら 元の状態にリジュームして 処理を継続する

Slide 28

Slide 28 text

go (Clojure) マルチコア対応 実際は、各ステートマシンの処理が 固定長スレッドプール上のスレッドに 割当てられることになる プールサイズはコア数に比例 2 * cores + 42

Slide 29

Slide 29 text

なるほど、軽量スレッド

Slide 30

Slide 30 text

OSおよび軽量スレッド/イメージ図 multi thread (OS) lightweight thread lightweight thread for multi core サーバアーキテクチャで、まずイベント駆動が流行して その後コア数に合わせてイベント駆動プロセスを立ち上げるのが出てきた経緯に似てるなあ

Slide 31

Slide 31 text

※CPUバウンド

Slide 32

Slide 32 text

IOバウンドな処理だと ● OSのスレッドを使った方がよい ● 軽量スレッドだと処理がブロックされる ● IO waitのコストがコンテキストスイッチのコスト を上回る ● ので、多量に並列するならスレッド上限が多く なっていることは確認しておく core.async なら thread マクロでそれでき(ry

Slide 33

Slide 33 text

まとめ ● go な並行処理はスッキリ記述できて嬉しい ● CPUリソースも無駄なく使えて嬉しい ● ただしマルチコアによる並「列」化は意識してお く ● そしてIOバウンドな処理にも気をつける ● あと、go マクロでステート・マシンに展開すると かヤバい