Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
チャネルの仕組み
Search
Kenshi Kamata
April 16, 2018
Programming
6
5.2k
チャネルの仕組み
2018/04/16 golang.tokyo #14 の発表です
Kenshi Kamata
April 16, 2018
Tweet
Share
More Decks by Kenshi Kamata
See All by Kenshi Kamata
500万ユーザーを支える残高の冪等性 / The idempotency of the balance for 5 million Merpay users
knsh14
0
2.6k
Go1.10 strings.Builder の紹介
knsh14
2
1.3k
Go でインタプリタを 書いてみよう
knsh14
0
2.8k
Let’s Create An Interpreter In Go
knsh14
0
120
Go Code Review Comment を翻訳した話
knsh14
0
7.3k
tvOS Leaderboard
knsh14
0
1.2k
Other Decks in Programming
See All in Programming
外部システム連携先が10を超えるシステムでのアーキテクチャ設計・実装事例
kiwasaki
1
280
Identifying User Idenity
moro
6
9.7k
Boost Performance and Developer Productivity with Jakarta EE 11
ivargrimstad
0
1.7k
Amazon Bedrock Agentsを用いてアプリ開発してみた!
har1101
0
320
Webの技術スタックで マルチプラットフォームアプリ開発を可能にするElixirDesktopの紹介
thehaigo
2
1k
Why Jakarta EE Matters to Spring - and Vice Versa
ivargrimstad
0
830
TypeScript Graph でコードレビューの心理的障壁を乗り越える
ysk8hori
1
390
ローコードSaaSのUXを向上させるためのTypeScript
taro28
1
400
LLM生成文章の精度評価自動化とプロンプトチューニングの効率化について
layerx
PRO
2
180
みんなでプロポーザルを書いてみた
yuriko1211
0
230
見せてあげますよ、「本物のLaravel批判」ってやつを。
77web
7
7.5k
AWS Lambdaから始まった Serverlessの「熱」とキャリアパス / It started with AWS Lambda Serverless “fever” and career path
seike460
PRO
1
220
Featured
See All Featured
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.1k
Building Applications with DynamoDB
mza
90
6.1k
VelocityConf: Rendering Performance Case Studies
addyosmani
325
24k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
280
13k
Designing on Purpose - Digital PM Summit 2013
jponch
115
7k
Building an army of robots
kneath
302
42k
10 Git Anti Patterns You Should be Aware of
lemiorhan
654
59k
Git: the NoSQL Database
bkeepers
PRO
427
64k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
226
22k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
109
49k
Designing Experiences People Love
moore
138
23k
4 Signs Your Business is Dying
shpigford
180
21k
Transcript
チャネルのしくみ golang.tokyo #14
自己紹介 • 鎌田健史 • KLab 株式会社 ◦ Unity でエディタ拡張書いたり ◦
JS でミニゲーム作ってたり ◦ 最近は Python ツールのサポート • Women Who Go のハンズオンのお手 伝い
資料 動画
帰ってやってほしいこと • GopherCon の発表を調べてみる ◦ 20 分くらいの発表 + 資料 •
実際に channel のソースコードを読んで見る
話したいこと • チャネルのおさらい • チャネルの構造 ◦ バッファありチャネルのデータ保存の仕組み • チャネルとデータの送受信の仕組み ◦
シンプルなやり取り ◦ 処理をブロックするとき
channel のおさらい https://go-tour-jp.appspot.com/concurrency/2 • goroutine 間で競合を起こさずにデータをやり取りする仕組み • Queue を持っていてデータを保存できる •
やり取りするデータの型を持っている goroutine1 goroutine2 chan
channel のおさらい • データのやり取りは FIFO • channel とやり取りできない場合、処理をブロックする • データをやりとり出来るようになると処理を再開する
• close(chan) することで送信側の終了を伝えることができる ◦ range ループで受け取っているときなど
コード例 Playgroundで試す
channel の構造 • チャネルには2種類ある ◦ バッファあり/なし • 実装 ◦ https://golang.org/src/runtime/chan.go#L31
• chan T で生成されるものは実は hchan 構造体のポインタ • メモリ上のヒープ領域に配置される
hchan の構造
バッファありチャネルの内部 • buf ◦ データを持つための配列への unsafe.Pointer • lock ◦ チャネルとデータのやり取りをするときにロックを取る
• sendx ◦ チャネルに送った場合に配列のどこに置かれるか • recvx ◦ チャネルから取り出すときにどの位置から出すか
バッファありチャネル • 生成時に容量を指定するとバッファありチャネル • ch := make(chan string, 10) buf
sendx = 0 lock recvx = 0 ・・・ 0 1 ・・・ 9
バッファありチャネル • 要素を追加すると... buf sendx = 1 lock recvx =
0 0 1 ・・・ 9 ch <- “hello” 0 1 ・・・ 9
バッファありチャネル • 要素を追加すると... buf sendx = 2 lock recvx =
0 0 1 ・・・ 9 0 1 ・・・ 9
バッファありチャネル • 一杯になると... buf sendx = 0 lock recvx =
0 0 1 ・・・ 9 0 1 ・・・ 9
バッファありチャネル • 要素を取りだすと... buf sendx = 0 lock recvx =
1 0 1 ・・・ 9 0 1 ・・・ 9
まとめ • chan T の実態は hchan のポインタ • バッファありチャネルのバッファは FIFO
• その実装はデータを取り出すためのインデックスとデータを受け取 るためのインデックスで実装されている
チャネルの送受信
シンプルな送受信 1. ロックを取る 2. バッファにコピー/バッファからコピー 3. ロック解除
送信 buf sendx = 0 lock recvx = 0 0
1 ・・・ 9 0 1 ・・・ 9
送信 buf sendx = 0 lock recvx = 0 0
1 ・・・ 9 0 1 ・・・ 9
送信 buf sendx = 0 lock recvx = 0 0
1 ・・・ 9 0 1 ・・・ 9
送信 buf sendx = 1 lock recvx = 0 0
1 ・・・ 9 0 1 ・・・ 9
送信 buf sendx = 1 lock recvx = 0 0
1 ・・・ 9 0 1 ・・・ 9
受信 buf sendx = 1 lock recvx = 0 0
1 ・・・ 9
受信 buf sendx = 1 lock recvx = 0 0
1 ・・・ 9
受信 buf sendx = 1 lock recvx = 0 0
1 ・・・ 9
受信 buf sendx = 1 lock recvx = 1 0
1 ・・・ 9
バッファを超える送信をした場合 buf sendx = 0 lock recvx = 0 0
1 ・・・ 9
バッファを超える送信をした場合 buf sendx = 0 lock recvx = 0 0
1 ・・・ 9 送信をブロックしなければいけない
寄り道: goroutine のスケジューリングの話 • M:N thread モデル ◦ M 個の
OS thread で N 個のgoroutine を分担して動かす • それぞれの OS thread に goroutine の Queue を持つ • キリが良いところまで実行して次の goroutine を実行する
G M(OS thread) G G(goroutine) P(Context of Scheduling)
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) ・・・
参考資料 • Goならわかるシステムプログラミング - Go言語と並列処理(2) • Go のスケジューラ実装とハマりポイント
送信をブロックする 1. スケジューラに対して止めるよう指示する(gopark) 2. OS thread は対象の goroutine を止めて実行から外す 3.
次の goroutine を実行する
G M(OS thread) G G(goroutine) P(Context of Scheduling)
G G M(OS thread) G G(goroutine) P(Context of Scheduling) ch
<- "schlusco"
channel から見たブロック • goroutine を停止する命令を投げる • 今の goroutine と送信用の値を Queue
に保存
buf lock sendq recvq sudog g elem Function01 schlusco
goroutine の再開 • シンプルに取りだす処理を行う • sudog にある要素を取りだして buf に追加 •
sudog にある goroutine を実行待ち状態にする
buf lock sendq recvq sudog g elem Function01 schlusco 0
1 ・・・ 9
buf lock sendq recvq sudog g elem Function01 schlusco 0
1 ・・・ 9
buf lock sendq recvq sudog g elem Function01 schlusco 0
1 ・・・ 9
buf lock sendq recvq sudog g elem Function01 schlusco 0
1 ・・・ 9
G G M(OS thread) G G(goroutine) P(Context of Scheduling)
受信側がブロックする場合 • 基本的に送信側がブロックする場合と逆
G M(OS thread) G G(goroutine) P(Context of Scheduling)
G G M(OS thread) G G(goroutine) P(Context of Scheduling) food
:= <-ch
buf lock sendq recvq sudog g elem Function02 food
goroutine を再開 • 送信処理を行う • sudog にある要素に buf の内容を渡す •
sudog にある goroutine を実行待ち状態にする
buf lock sendq recvq sudog g elem Function02 food 0
1 ・・・ 9
buf lock sendq recvq sudog g elem Function02 food 0
1 ・・・ 9
buf lock sendq recvq sudog g elem Function02 food :=
“sushi” 0 1 ・・・ 9
buf lock sendq recvq sudog g elem Function02 food :=
“sushi” 0 1 ・・・ 9
もっと賢く • sudog の elem は受取先のポインタ • なのでここに直接書いてしまえばOK! • メモリコピーと
lock を取る回数も減って嬉しい
buf lock sendq recvq sudog g elem Function02 food 0
1 ・・・ 9
buf lock sendq recvq sudog g elem Function02 food :=
“sushi” 0 1 ・・・ 9
バッファなしチャネルの話 • 基本的にこれまで話してきたことと同じ • バッファがないので常にブロックが発生する
Select で使う場合 • 全部の channel をロックする • 全部の channel の
sudog に自分を入れて待ち状態にする • 勝った case のところから処理を再開する
まとめ • channel は使い方はシンプル • だけど裏ではしっかり並列処理のための仕組みが動いている • 発表資料はとても勉強になった ◦ Gopher
Con は行けないけど他の資料も見ていきたい