Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
チャネルのしくみ golang.tokyo #14
Slide 2
Slide 2 text
自己紹介 ● 鎌田健史 ● KLab 株式会社 ○ Unity でエディタ拡張書いたり ○ JS でミニゲーム作ってたり ○ 最近は Python ツールのサポート ● Women Who Go のハンズオンのお手 伝い
Slide 3
Slide 3 text
資料 動画
Slide 4
Slide 4 text
帰ってやってほしいこと ● GopherCon の発表を調べてみる ○ 20 分くらいの発表 + 資料 ● 実際に channel のソースコードを読んで見る
Slide 5
Slide 5 text
話したいこと ● チャネルのおさらい ● チャネルの構造 ○ バッファありチャネルのデータ保存の仕組み ● チャネルとデータの送受信の仕組み ○ シンプルなやり取り ○ 処理をブロックするとき
Slide 6
Slide 6 text
channel のおさらい https://go-tour-jp.appspot.com/concurrency/2 ● goroutine 間で競合を起こさずにデータをやり取りする仕組み ● Queue を持っていてデータを保存できる ● やり取りするデータの型を持っている goroutine1 goroutine2 chan
Slide 7
Slide 7 text
channel のおさらい ● データのやり取りは FIFO ● channel とやり取りできない場合、処理をブロックする ● データをやりとり出来るようになると処理を再開する ● close(chan) することで送信側の終了を伝えることができる ○ range ループで受け取っているときなど
Slide 8
Slide 8 text
コード例 Playgroundで試す
Slide 9
Slide 9 text
channel の構造 ● チャネルには2種類ある ○ バッファあり/なし ● 実装 ○ https://golang.org/src/runtime/chan.go#L31 ● chan T で生成されるものは実は hchan 構造体のポインタ ● メモリ上のヒープ領域に配置される
Slide 10
Slide 10 text
hchan の構造
Slide 11
Slide 11 text
バッファありチャネルの内部 ● buf ○ データを持つための配列への unsafe.Pointer ● lock ○ チャネルとデータのやり取りをするときにロックを取る ● sendx ○ チャネルに送った場合に配列のどこに置かれるか ● recvx ○ チャネルから取り出すときにどの位置から出すか
Slide 12
Slide 12 text
バッファありチャネル ● 生成時に容量を指定するとバッファありチャネル ● ch := make(chan string, 10) buf sendx = 0 lock recvx = 0 ・・・ 0 1 ・・・ 9
Slide 13
Slide 13 text
バッファありチャネル ● 要素を追加すると... buf sendx = 1 lock recvx = 0 0 1 ・・・ 9 ch <- “hello” 0 1 ・・・ 9
Slide 14
Slide 14 text
バッファありチャネル ● 要素を追加すると... buf sendx = 2 lock recvx = 0 0 1 ・・・ 9 0 1 ・・・ 9
Slide 15
Slide 15 text
バッファありチャネル ● 一杯になると... buf sendx = 0 lock recvx = 0 0 1 ・・・ 9 0 1 ・・・ 9
Slide 16
Slide 16 text
バッファありチャネル ● 要素を取りだすと... buf sendx = 0 lock recvx = 1 0 1 ・・・ 9 0 1 ・・・ 9
Slide 17
Slide 17 text
まとめ ● chan T の実態は hchan のポインタ ● バッファありチャネルのバッファは FIFO ● その実装はデータを取り出すためのインデックスとデータを受け取 るためのインデックスで実装されている
Slide 18
Slide 18 text
チャネルの送受信
Slide 19
Slide 19 text
シンプルな送受信 1. ロックを取る 2. バッファにコピー/バッファからコピー 3. ロック解除
Slide 20
Slide 20 text
送信 buf sendx = 0 lock recvx = 0 0 1 ・・・ 9 0 1 ・・・ 9
Slide 21
Slide 21 text
送信 buf sendx = 0 lock recvx = 0 0 1 ・・・ 9 0 1 ・・・ 9
Slide 22
Slide 22 text
送信 buf sendx = 0 lock recvx = 0 0 1 ・・・ 9 0 1 ・・・ 9
Slide 23
Slide 23 text
送信 buf sendx = 1 lock recvx = 0 0 1 ・・・ 9 0 1 ・・・ 9
Slide 24
Slide 24 text
送信 buf sendx = 1 lock recvx = 0 0 1 ・・・ 9 0 1 ・・・ 9
Slide 25
Slide 25 text
受信 buf sendx = 1 lock recvx = 0 0 1 ・・・ 9
Slide 26
Slide 26 text
受信 buf sendx = 1 lock recvx = 0 0 1 ・・・ 9
Slide 27
Slide 27 text
受信 buf sendx = 1 lock recvx = 0 0 1 ・・・ 9
Slide 28
Slide 28 text
受信 buf sendx = 1 lock recvx = 1 0 1 ・・・ 9
Slide 29
Slide 29 text
バッファを超える送信をした場合 buf sendx = 0 lock recvx = 0 0 1 ・・・ 9
Slide 30
Slide 30 text
バッファを超える送信をした場合 buf sendx = 0 lock recvx = 0 0 1 ・・・ 9 送信をブロックしなければいけない
Slide 31
Slide 31 text
寄り道: goroutine のスケジューリングの話 ● M:N thread モデル ○ M 個の OS thread で N 個のgoroutine を分担して動かす ● それぞれの OS thread に goroutine の Queue を持つ ● キリが良いところまで実行して次の goroutine を実行する
Slide 32
Slide 32 text
G M(OS thread) G G(goroutine) P(Context of Scheduling)
Slide 33
Slide 33 text
M 個の OS thread G M(OS thread) G G(goroutine) P(Context of Scheduling) G M(OS thread) G G(goroutine) P(Context of Scheduling) ・・・
Slide 34
Slide 34 text
参考資料 ● Goならわかるシステムプログラミング - Go言語と並列処理(2) ● Go のスケジューラ実装とハマりポイント
Slide 35
Slide 35 text
送信をブロックする 1. スケジューラに対して止めるよう指示する(gopark) 2. OS thread は対象の goroutine を止めて実行から外す 3. 次の goroutine を実行する
Slide 36
Slide 36 text
G M(OS thread) G G(goroutine) P(Context of Scheduling)
Slide 37
Slide 37 text
G G M(OS thread) G G(goroutine) P(Context of Scheduling) ch <- "schlusco"
Slide 38
Slide 38 text
channel から見たブロック ● goroutine を停止する命令を投げる ● 今の goroutine と送信用の値を Queue に保存
Slide 39
Slide 39 text
buf lock sendq recvq sudog g elem Function01 schlusco
Slide 40
Slide 40 text
goroutine の再開 ● シンプルに取りだす処理を行う ● sudog にある要素を取りだして buf に追加 ● sudog にある goroutine を実行待ち状態にする
Slide 41
Slide 41 text
buf lock sendq recvq sudog g elem Function01 schlusco 0 1 ・・・ 9
Slide 42
Slide 42 text
buf lock sendq recvq sudog g elem Function01 schlusco 0 1 ・・・ 9
Slide 43
Slide 43 text
buf lock sendq recvq sudog g elem Function01 schlusco 0 1 ・・・ 9
Slide 44
Slide 44 text
buf lock sendq recvq sudog g elem Function01 schlusco 0 1 ・・・ 9
Slide 45
Slide 45 text
G G M(OS thread) G G(goroutine) P(Context of Scheduling)
Slide 46
Slide 46 text
受信側がブロックする場合 ● 基本的に送信側がブロックする場合と逆
Slide 47
Slide 47 text
G M(OS thread) G G(goroutine) P(Context of Scheduling)
Slide 48
Slide 48 text
G G M(OS thread) G G(goroutine) P(Context of Scheduling) food := <-ch
Slide 49
Slide 49 text
buf lock sendq recvq sudog g elem Function02 food
Slide 50
Slide 50 text
goroutine を再開 ● 送信処理を行う ● sudog にある要素に buf の内容を渡す ● sudog にある goroutine を実行待ち状態にする
Slide 51
Slide 51 text
buf lock sendq recvq sudog g elem Function02 food 0 1 ・・・ 9
Slide 52
Slide 52 text
buf lock sendq recvq sudog g elem Function02 food 0 1 ・・・ 9
Slide 53
Slide 53 text
buf lock sendq recvq sudog g elem Function02 food := “sushi” 0 1 ・・・ 9
Slide 54
Slide 54 text
buf lock sendq recvq sudog g elem Function02 food := “sushi” 0 1 ・・・ 9
Slide 55
Slide 55 text
もっと賢く ● sudog の elem は受取先のポインタ ● なのでここに直接書いてしまえばOK! ● メモリコピーと lock を取る回数も減って嬉しい
Slide 56
Slide 56 text
buf lock sendq recvq sudog g elem Function02 food 0 1 ・・・ 9
Slide 57
Slide 57 text
buf lock sendq recvq sudog g elem Function02 food := “sushi” 0 1 ・・・ 9
Slide 58
Slide 58 text
バッファなしチャネルの話 ● 基本的にこれまで話してきたことと同じ ● バッファがないので常にブロックが発生する
Slide 59
Slide 59 text
Select で使う場合 ● 全部の channel をロックする ● 全部の channel の sudog に自分を入れて待ち状態にする ● 勝った case のところから処理を再開する
Slide 60
Slide 60 text
まとめ ● channel は使い方はシンプル ● だけど裏ではしっかり並列処理のための仕組みが動いている ● 発表資料はとても勉強になった ○ Gopher Con は行けないけど他の資料も見ていきたい