SlideShare a Scribd company logo
1 of 63
Go Contextを完全に理解する
伊藤 真彦
The Gopher character is based on the Go mascot designed by Renée French
伊藤真彦 Masahiko Ito
フューチャー株式会社 TIG DXチーム所属
担当領域: コンサルタントとしてなんでもやっています
趣味: ギター
資格:
@it_guitar
自己紹介
フューチャーは
ITコンサルティングを中心に開発、保守までを
一気通貫の体制で行う会社です。
自己紹介
自己紹介
発表のモチベーション
● よくわからないまま使っている機能があるので理解したかった
○ 例: ポインタ、2020年のGoアドベントカレンダーのネタにした
● contextが期待通りの状態になっているかデバッグするのに苦労した、
発表を通してしっかり理解し、また理解できるコンテンツを作りたい
● contextは少ない行でGoのテクニックをたくさん使っている
実装を深堀すると学びになる
Contextとは
Contextとは
contextはAPIの境界を越えて、プロセス間で、期限、キャンセルシグナル、
およびその他のリクエストスコープの値を伝達します
採用したライブラリがContextを渡してくれる→後続処理に渡す
これだけで複雑な並行処理であってもタイムアウトやキャンセルの制御が可能
https://pkg.go.dev/context
Contextとは
例: AWS SDKのLambdaハンドラ→Amazon Dynamo DB SDKを利用したDBリクエスト
Contextとは
もちろん任意の実装も可能
例: 5秒間処理を繰り返す
https://play.golang.org/p/HBDan3ykITr
Contextとは
例: Go 1.16のsignal.NotifyContext()を用いたgracefulシャットダウン
詳しくは
https://future-architect.github.io/articles/20210212/
Contextとは
zennの記事、出た(無料)
Contextとは
タイムライン(言い訳)
プロポーザル提出 zenn無料書籍公開 プロポーザル採択
2021/08/03 2021/08/28 2021/09/15
Contextとは
逆に言うと内部実装の理解にフォーカスできます、素晴らしい情報に感謝
Contextの内部実装
Contextの内部実装
Contextは発表段階(2021年10月)で593行で実装されています
https://github.com/golang/go/blob/master/
src/context/context.go
Contextの内部実装
Contextはinterfaceです
Contextの内部実装
序盤はコメントが多いので、これだけで154行まで説明が済みます
Contextの内部実装
次にキャンセル、タイムアウト時に所定のメッセージを返すための
エラーが定義されています
timeOut(), Temporary()は内部では利用されていません
netパッケージで提供されているエラーと同じインターフェース仕様を満たすことで
呼び出し元でのリトライ実行の制御などに役立てることができます
Contextの内部実装
参考: netパッケージのError interface
https://github.com/golang/go/blob/master/src/net/net.go#L397
使い方イメージ
Contextの内部実装
ContextのベースとなるemptyCtxが定義されています
intがベースとなっているのはこの型の値の全てが
異なるアドレスを持つようにするためです
Interfaceとしての仕様を満たす関数を備えつつ、
それぞれの型の0値を返します
Deadline()で名前付きの戻り値を利用することで、
return一行で
0001-01-01 00:00:00 +0000 UTC, false
を返却するのはGoにしては珍しいトリッキーな書き方
String()だけはbackgroundとtodoを区別するための
switch文が書かれています
Contextの内部実装
background, todoはvarで定義されています
context.TODO()、のような使い方でそれぞれのemptyCtxを取得します
backgroundとtodoの違いis 何?
持っている機能としては100%同じ
後続の処理で区別するような記述は一切なし
可読性のために使い分け
context.Background()
これからデッドラインなどを仕込むための準備とし
て呼び出す
context.TODO()
contextの用途が明確ではない、もしくは必要か明
確に定まっていないときに呼び出す
backgroundを使うべき状況でtodoを使っても機能的
には問題ない
Contextの内部実装
> 値の全てが異なるアドレスを持つようにするため
何のことを言っているのかは試してみると理解できます
Contextの内部実装
220行目からキャンセル機能が実装されています
構造体cancelCtxは340行目で定義されています
WithCancelで親のContextを与えると、そ
れを取り込んだcancelCtxと
キャンセルのための関数が取得できます
この設計からcontextの親子関係の仕組み
が推察できます
Contextの内部実装
245行目で親のキャンセル情報を子に伝播するための実装が行われています
contextの中では比較的複雑な実装です
親コンテキストがキャンセル済でない
cancelCtxの場合は親コンテキストのキャ
ンセルを伝播させる対象を集めるmapに子
コンテキストを詰め込みます
Contextの内部実装
少々難しい処理ですが、parentCancelCtxで親contextの状態、型を確認しながら
キャンセル状況を伝播させるか否か整理しています
実装部分のコメントを翻訳
parentCancelCtxは、親の基になる* cancelCtxを返し
ます。
これは、parent.Value(&cancelCtxKey)を検索し
て見つけることによって行われます。
最も内側の囲んでいる* cancelCtxをチェックし、
parent.Done()はその* cancelCtxと一致します。
(そうでない場合、* cancelCtx
別の完了チャネルを提供するカスタム実装にラップ
されています。その場合、それをバイパスしないで
ください。)
Contextの内部実装
312行目で後々の行で利用するremoveChildが実装されています
親contextにcancelCtxが存在する場合、ロックをかけながらchildrenの情報を削除
します、delete()はGoの組み込み関数です
Contextの内部実装
326行目でcancelerが定義されています
cacelerの実態はcancelCtxなどcontext自身です
Contextの内部実装
333行目〜closedchanとcancelCtxが定義されています
Contextの内部実装
351行目〜cancelCtxのValue, Done, Errが定義されています
Contextの内部実装
380行目~ String()とそれで用いる関数が定義されています
StringはinterfaceとしてのContextに定義されていないため、直接呼び出すことは
できません
Contextの内部実装
できない できる
Contextの内部実装
正しい使い方
Contextの内部実装
397行目〜 cancelが実装されています
WithCancelで取得できる関数です
Contextの内部実装
425行目〜 WithDeadLineが実装されています
DeadLine時刻が既に過ぎているか、親のコンテキス
トにより短いデッドラインが存在するか、など保険と
なる実装がありますが、
基本的には引数で与えたDeadline時刻をタイマーとし
てセットしています
Contextの内部実装
time.AfterFuncの存在は覚えておきたい
Contextの内部実装
465行目にtimerCtxが定義されています
cancelCtxがフィールドに埋め込まれており、timerCtxはcancelCtxの拡張であるこ
とがわかります
Contextの内部実装
func (t *timerCtx) Done()のような記述は一切ありませんが、
構造体の埋め込みによりtimerCtxはcancelerのインターフェース仕様を
満たしています
Contextの内部実装
一方cancelは埋め込んだcancelCtxのcancelを呼び出しつつ、
タイマーを掃除するtimerCtx独自のものが実装されています
Contextの内部実装
472行目〜 DeadLine()が実装されています
emptyCtxと比較すると0値でない値が取得できていることがわかります
cancelCtxは独自のDeadline関数を持たず、埋め込まれた親コンテキストのDeadline
を呼んでいます
参考: 今まで出てきたCtx
Contextの内部実装
476行目~ timerCtxのString()が実装されています
参考: 今まで出てきたCtx
Contextの内部実装
496行目〜 WithTimeoutが実装されています
WithDeadlineのラッパーであることがわかります
Contextの内部実装
510行目〜 WithValueが定義されています
keyもvalueもinterface{}です
Contextの内部実装
valueCtxは親Contextとkey, valを持った比較的シンプルな構造体です
Contextの内部実装
valueCtxも独自のString()関数を持っています
stringify は、fmt を使わずに v を文字列化しよ
うと少しだけ試みます。
というのは、
私たちはcontextがunicodeテーブルに依存する
事を望まないからです。
これは*ValueCtx.String()でのみ使用されます
。
Contextの内部実装
fmtパッケージを使うとバイナリサイズに800KBほど影響が及ぶ
Contextの内部実装
ポイント: contextはPrint関数で表示されない情報は持っていない
参考: https://future-architect.github.io/articles/20201112/
Contextの内部実装
クライアントでlambda関数を起動、渡すctxにvalueを詰める
AWS Lambdaの上で実行されるコードでcontextを利用
しかしctxに詰めたvalueが取得できない
一度HTTPリクエストを経由する都合上valueは失われる(値の伝達はPayload使え)
という結論に至るまでに結構プリントデバッグした
プリントデバッグした時点でValueが表示されなかったらValueは存在しない事を知
っておけば自信を持って早期に結論を出せた
Contextの内部実装
valueCtxの目玉機能のValue関数が実装されています
各Context特有の挙動をとりつつ、
emptyCtx以外は後述するvalueを呼び出します
参考: 今まで出てきたCtx
Contextの内部実装
Valueに渡す値は==で一致するものであればなんでも良いですが
メモリ効率を考えるとint型の変数のポインタを投げるのが推奨(?)
内部ではそうしているだけですが
Contextの内部実装
ポインタ型を投げなくてももちろん動きます
文字列などでラフに値を取り出したいか
keyの重複を考慮せずに済む方が良いかで使い分けできます
Contextの内部実装
最後に内部で呼び出されるvalue関数の実装をもって593行が終了です
keyがヒットするかemptyCtxにたどり着くまで
無限に各context型のValueとほぼ同じことをします
再帰関数になりそうでならない実装です
まとめ
まとめ
● interface仕様を満たした4種類の〇〇Ctxが存在する
● これらCtxを親子関係としてネストできる
まとめ
学びになるポイント
● Interfaceの使い方
● 型アサーションを用いるswitch文の使い方
まとめ
学びになるポイント
● 独自のエラー型の使い方
まとめ
学びになるポイント
● sync.Mutexの使い方
まとめ
学びになるポイント
● channelの使い方
まとめ
学びになるポイント
● sync/atomicの使い方
まとめ
学びになるポイント
● intを拡張した型を利用する
まとめ
学びになるポイント
● 名前付き変数によるreturn文の簡略化
まとめ
学びになるポイント
● 構造体に構造体、インターフェースを埋め込む
まとめ
学びになるポイント
● 順番が重要でない、任意の値が入っているか確認できれば良い
コレクションはkeyに使いたい値を詰めたmapにする
改めてpropagateCancel関数と、
それを呼び出している実装を見直すと参考になると思います
まとめ
Goはシンプルであれが足りない、とか言うけど
言うほどGoを使いこなしてる?
技術を読む
人・企業を知る
技術を聴く
勉強会に参加する
フューチャーの技術ブログ。
業務で利用している幅広い技術について
、最新のトピックを交えて紹介します。
フューチャーの技術者によるポッドキャスト。
技術の深堀りトークやブログ記事の裏に隠され
た秘話をお届けします。
フューチャーの人、カルチャー、イベントレ
ポートなどを幅広く発信。ありのままのフュ
ーチャーをタイムリーに紹介します。
未来報 connpass
エンジニアや IT コンサルタント向けの勉強会
を定期的に開催。フューチャーが業務を通して
得た技術的な知見やナレッジを共有します
Future Tech
Blog
Future Tech
Cast
https://future-architect.github.io/ https://anchor.fm/futuretechcast
https://note.future.co.jp/ https://future.connpass.com/
フューチャーをもっと知るには?

More Related Content

What's hot

[クリエイティブハント2018]LT 道場破りしたらできちゃった/// #ゴーハント
[クリエイティブハント2018]LT 道場破りしたらできちゃった/// #ゴーハント[クリエイティブハント2018]LT 道場破りしたらできちゃった/// #ゴーハント
[クリエイティブハント2018]LT 道場破りしたらできちゃった/// #ゴーハントHiroyuki Ishikawa
 
利根川講演@北海道20170113
利根川講演@北海道20170113利根川講演@北海道20170113
利根川講演@北海道20170113Yuta Tonegawa
 
Pythonの10年と今、これから
Pythonの10年と今、これからPythonの10年と今、これから
Pythonの10年と今、これからHaruo Sato
 
Hour of-code-2016冬-シンポジウム
Hour of-code-2016冬-シンポジウムHour of-code-2016冬-シンポジウム
Hour of-code-2016冬-シンポジウムYuta Tonegawa
 
新卒がモンストとファイトリーグリーグ開発で行ったこと
新卒がモンストとファイトリーグリーグ開発で行ったこと新卒がモンストとファイトリーグリーグ開発で行ったこと
新卒がモンストとファイトリーグリーグ開発で行ったことhogehoge14
 
プレゼンの技術
プレゼンの技術プレゼンの技術
プレゼンの技術心 谷本
 
Hello Engineer World! 新人リケジョの1年
Hello Engineer World! 新人リケジョの1年Hello Engineer World! 新人リケジョの1年
Hello Engineer World! 新人リケジョの1年Satoko Shiroi
 
プログラミング有識者会議を読み解く
プログラミング有識者会議を読み解くプログラミング有識者会議を読み解く
プログラミング有識者会議を読み解くYuta Tonegawa
 
プレゼンの技術 1 考え方
プレゼンの技術 1 考え方プレゼンの技術 1 考え方
プレゼンの技術 1 考え方心 谷本
 
20180826 learn languages 2018 in odc
20180826 learn languages 2018 in odc20180826 learn languages 2018 in odc
20180826 learn languages 2018 in odcTakayukiTakahashi4
 
CTOやフリーランスのキャリアについて
CTOやフリーランスのキャリアについてCTOやフリーランスのキャリアについて
CTOやフリーランスのキャリアについてYusuke Kon
 
CNCFアップデート情報~2018年のCNCFを振り返る
CNCFアップデート情報~2018年のCNCFを振り返るCNCFアップデート情報~2018年のCNCFを振り返る
CNCFアップデート情報~2018年のCNCFを振り返るMasahito Zembutsu
 
オンラインPython学習サービスPyQの価格決め
オンラインPython学習サービスPyQの価格決めオンラインPython学習サービスPyQの価格決め
オンラインPython学習サービスPyQの価格決めHaruo Sato
 
プログラミング教育シンポジウム@札幌 資料
プログラミング教育シンポジウム@札幌 資料プログラミング教育シンポジウム@札幌 資料
プログラミング教育シンポジウム@札幌 資料Yuta Tonegawa
 
Triz20200617_Univ_Tokyo
Triz20200617_Univ_TokyoTriz20200617_Univ_Tokyo
Triz20200617_Univ_Tokyo芳徳 高木
 
クラッシュフィーバーのシステム構成
クラッシュフィーバーのシステム構成クラッシュフィーバーのシステム構成
クラッシュフィーバーのシステム構成Tomotsune Murata
 
かなしき だるやなぎちゃん ~海老を獲りに行く話~
かなしき だるやなぎちゃん ~海老を獲りに行く話~かなしき だるやなぎちゃん ~海老を獲りに行く話~
かなしき だるやなぎちゃん ~海老を獲りに行く話~You&I
 
プログラミング教育の基礎知識
プログラミング教育の基礎知識プログラミング教育の基礎知識
プログラミング教育の基礎知識Masahito Zembutsu
 
Hour of code教材解説@福井
Hour of code教材解説@福井Hour of code教材解説@福井
Hour of code教材解説@福井Yuta Tonegawa
 

What's hot (19)

[クリエイティブハント2018]LT 道場破りしたらできちゃった/// #ゴーハント
[クリエイティブハント2018]LT 道場破りしたらできちゃった/// #ゴーハント[クリエイティブハント2018]LT 道場破りしたらできちゃった/// #ゴーハント
[クリエイティブハント2018]LT 道場破りしたらできちゃった/// #ゴーハント
 
利根川講演@北海道20170113
利根川講演@北海道20170113利根川講演@北海道20170113
利根川講演@北海道20170113
 
Pythonの10年と今、これから
Pythonの10年と今、これからPythonの10年と今、これから
Pythonの10年と今、これから
 
Hour of-code-2016冬-シンポジウム
Hour of-code-2016冬-シンポジウムHour of-code-2016冬-シンポジウム
Hour of-code-2016冬-シンポジウム
 
新卒がモンストとファイトリーグリーグ開発で行ったこと
新卒がモンストとファイトリーグリーグ開発で行ったこと新卒がモンストとファイトリーグリーグ開発で行ったこと
新卒がモンストとファイトリーグリーグ開発で行ったこと
 
プレゼンの技術
プレゼンの技術プレゼンの技術
プレゼンの技術
 
Hello Engineer World! 新人リケジョの1年
Hello Engineer World! 新人リケジョの1年Hello Engineer World! 新人リケジョの1年
Hello Engineer World! 新人リケジョの1年
 
プログラミング有識者会議を読み解く
プログラミング有識者会議を読み解くプログラミング有識者会議を読み解く
プログラミング有識者会議を読み解く
 
プレゼンの技術 1 考え方
プレゼンの技術 1 考え方プレゼンの技術 1 考え方
プレゼンの技術 1 考え方
 
20180826 learn languages 2018 in odc
20180826 learn languages 2018 in odc20180826 learn languages 2018 in odc
20180826 learn languages 2018 in odc
 
CTOやフリーランスのキャリアについて
CTOやフリーランスのキャリアについてCTOやフリーランスのキャリアについて
CTOやフリーランスのキャリアについて
 
CNCFアップデート情報~2018年のCNCFを振り返る
CNCFアップデート情報~2018年のCNCFを振り返るCNCFアップデート情報~2018年のCNCFを振り返る
CNCFアップデート情報~2018年のCNCFを振り返る
 
オンラインPython学習サービスPyQの価格決め
オンラインPython学習サービスPyQの価格決めオンラインPython学習サービスPyQの価格決め
オンラインPython学習サービスPyQの価格決め
 
プログラミング教育シンポジウム@札幌 資料
プログラミング教育シンポジウム@札幌 資料プログラミング教育シンポジウム@札幌 資料
プログラミング教育シンポジウム@札幌 資料
 
Triz20200617_Univ_Tokyo
Triz20200617_Univ_TokyoTriz20200617_Univ_Tokyo
Triz20200617_Univ_Tokyo
 
クラッシュフィーバーのシステム構成
クラッシュフィーバーのシステム構成クラッシュフィーバーのシステム構成
クラッシュフィーバーのシステム構成
 
かなしき だるやなぎちゃん ~海老を獲りに行く話~
かなしき だるやなぎちゃん ~海老を獲りに行く話~かなしき だるやなぎちゃん ~海老を獲りに行く話~
かなしき だるやなぎちゃん ~海老を獲りに行く話~
 
プログラミング教育の基礎知識
プログラミング教育の基礎知識プログラミング教育の基礎知識
プログラミング教育の基礎知識
 
Hour of code教材解説@福井
Hour of code教材解説@福井Hour of code教材解説@福井
Hour of code教材解説@福井
 

Similar to Go conference 2021 autumn

そうだ、Goを始めよう
そうだ、Goを始めようそうだ、Goを始めよう
そうだ、Goを始めようTakuya Ueda
 
ここがスゴい(変だ)よ!Git lab!
ここがスゴい(変だ)よ!Git lab!ここがスゴい(変だ)よ!Git lab!
ここがスゴい(変だ)よ!Git lab!Naoharu Sasaki
 
WebAssembly with Go
WebAssembly with GoWebAssembly with Go
WebAssembly with GoTakuya Ueda
 
タスク管理ツールJootoによるゲーム開発実例について
タスク管理ツールJootoによるゲーム開発実例についてタスク管理ツールJootoによるゲーム開発実例について
タスク管理ツールJootoによるゲーム開発実例についてyusuke hara
 
確定申告ってなんでやるの?.pdf
確定申告ってなんでやるの?.pdf確定申告ってなんでやるの?.pdf
確定申告ってなんでやるの?.pdfssusera9322b
 
エンジニアになり1ヶ月が経って!
エンジニアになり1ヶ月が経って!エンジニアになり1ヶ月が経って!
エンジニアになり1ヶ月が経って!ssuserccd9f1
 
第7回SIA研究会(例会)プレゼン資料 油野様
第7回SIA研究会(例会)プレゼン資料 油野様第7回SIA研究会(例会)プレゼン資料 油野様
第7回SIA研究会(例会)プレゼン資料 油野様Tae Yoshida
 
採用ピッチ資料_2023
採用ピッチ資料_2023採用ピッチ資料_2023
採用ピッチ資料_2023Flyke1
 
Go初心者向けハンズオン コマンドラインツールを作ろう
Go初心者向けハンズオン コマンドラインツールを作ろうGo初心者向けハンズオン コマンドラインツールを作ろう
Go初心者向けハンズオン コマンドラインツールを作ろうTakuya Ueda
 
RTC2023_ChatGPT_YukiTsukamae.pdf
RTC2023_ChatGPT_YukiTsukamae.pdfRTC2023_ChatGPT_YukiTsukamae.pdf
RTC2023_ChatGPT_YukiTsukamae.pdfhossenkamal2
 
RTC2023_ChatGPT_YukiTsukamae.pptx
RTC2023_ChatGPT_YukiTsukamae.pptxRTC2023_ChatGPT_YukiTsukamae.pptx
RTC2023_ChatGPT_YukiTsukamae.pptxhossenkamal2
 
一生、エンジニアであり続けるために必要なこと「負けてからのエンジニアライフ」
一生、エンジニアであり続けるために必要なこと「負けてからのエンジニアライフ」一生、エンジニアであり続けるために必要なこと「負けてからのエンジニアライフ」
一生、エンジニアであり続けるために必要なこと「負けてからのエンジニアライフ」雄哉 吉田
 
メルカリ カウルのマスタデータの更新
メルカリ カウルのマスタデータの更新メルカリ カウルのマスタデータの更新
メルカリ カウルのマスタデータの更新Takuya Ueda
 
Goにおけるバージョン管理の必要性 − vgoについて −
Goにおけるバージョン管理の必要性 − vgoについて −Goにおけるバージョン管理の必要性 − vgoについて −
Goにおけるバージョン管理の必要性 − vgoについて −Takuya Ueda
 
enPiT修了生は、大学卒業後の一歩をどう選んだか
enPiT修了生は、大学卒業後の一歩をどう選んだかenPiT修了生は、大学卒業後の一歩をどう選んだか
enPiT修了生は、大学卒業後の一歩をどう選んだかShizuru Kosuge
 
Contribute to terraform-provider-aws
Contribute to terraform-provider-awsContribute to terraform-provider-aws
Contribute to terraform-provider-aws健太郎 平松
 
10数年運用されているシステムの紐解き方
10数年運用されているシステムの紐解き方10数年運用されているシステムの紐解き方
10数年運用されているシステムの紐解き方amano shohei
 

Similar to Go conference 2021 autumn (20)

そうだ、Goを始めよう
そうだ、Goを始めようそうだ、Goを始めよう
そうだ、Goを始めよう
 
ここがスゴい(変だ)よ!Git lab!
ここがスゴい(変だ)よ!Git lab!ここがスゴい(変だ)よ!Git lab!
ここがスゴい(変だ)よ!Git lab!
 
WebAssembly with Go
WebAssembly with GoWebAssembly with Go
WebAssembly with Go
 
タスク管理ツールJootoによるゲーム開発実例について
タスク管理ツールJootoによるゲーム開発実例についてタスク管理ツールJootoによるゲーム開発実例について
タスク管理ツールJootoによるゲーム開発実例について
 
確定申告ってなんでやるの?.pdf
確定申告ってなんでやるの?.pdf確定申告ってなんでやるの?.pdf
確定申告ってなんでやるの?.pdf
 
[XP祭り2020]組織にはびこるなんちゃってスクラムからの脱却を目指して
[XP祭り2020]組織にはびこるなんちゃってスクラムからの脱却を目指して[XP祭り2020]組織にはびこるなんちゃってスクラムからの脱却を目指して
[XP祭り2020]組織にはびこるなんちゃってスクラムからの脱却を目指して
 
エンジニアになり1ヶ月が経って!
エンジニアになり1ヶ月が経って!エンジニアになり1ヶ月が経って!
エンジニアになり1ヶ月が経って!
 
第7回SIA研究会(例会)プレゼン資料 油野様
第7回SIA研究会(例会)プレゼン資料 油野様第7回SIA研究会(例会)プレゼン資料 油野様
第7回SIA研究会(例会)プレゼン資料 油野様
 
agatsuma.survive#5
agatsuma.survive#5agatsuma.survive#5
agatsuma.survive#5
 
採用ピッチ資料_2023
採用ピッチ資料_2023採用ピッチ資料_2023
採用ピッチ資料_2023
 
Go初心者向けハンズオン コマンドラインツールを作ろう
Go初心者向けハンズオン コマンドラインツールを作ろうGo初心者向けハンズオン コマンドラインツールを作ろう
Go初心者向けハンズオン コマンドラインツールを作ろう
 
RTC2023_ChatGPT_YukiTsukamae.pdf
RTC2023_ChatGPT_YukiTsukamae.pdfRTC2023_ChatGPT_YukiTsukamae.pdf
RTC2023_ChatGPT_YukiTsukamae.pdf
 
RTC2023_ChatGPT_YukiTsukamae.pptx
RTC2023_ChatGPT_YukiTsukamae.pptxRTC2023_ChatGPT_YukiTsukamae.pptx
RTC2023_ChatGPT_YukiTsukamae.pptx
 
一生、エンジニアであり続けるために必要なこと「負けてからのエンジニアライフ」
一生、エンジニアであり続けるために必要なこと「負けてからのエンジニアライフ」一生、エンジニアであり続けるために必要なこと「負けてからのエンジニアライフ」
一生、エンジニアであり続けるために必要なこと「負けてからのエンジニアライフ」
 
メルカリ カウルのマスタデータの更新
メルカリ カウルのマスタデータの更新メルカリ カウルのマスタデータの更新
メルカリ カウルのマスタデータの更新
 
Goにおけるバージョン管理の必要性 − vgoについて −
Goにおけるバージョン管理の必要性 − vgoについて −Goにおけるバージョン管理の必要性 − vgoについて −
Goにおけるバージョン管理の必要性 − vgoについて −
 
enPiT修了生は、大学卒業後の一歩をどう選んだか
enPiT修了生は、大学卒業後の一歩をどう選んだかenPiT修了生は、大学卒業後の一歩をどう選んだか
enPiT修了生は、大学卒業後の一歩をどう選んだか
 
アンラーニング
アンラーニングアンラーニング
アンラーニング
 
Contribute to terraform-provider-aws
Contribute to terraform-provider-awsContribute to terraform-provider-aws
Contribute to terraform-provider-aws
 
10数年運用されているシステムの紐解き方
10数年運用されているシステムの紐解き方10数年運用されているシステムの紐解き方
10数年運用されているシステムの紐解き方
 

Recently uploaded

動的 & 非同期コンポーネント / Dynamic & Async Components
動的 & 非同期コンポーネント / Dynamic & Async Components動的 & 非同期コンポーネント / Dynamic & Async Components
動的 & 非同期コンポーネント / Dynamic & Async Componentsokitamasashi
 
Windows 10、Windows 11の付箋を簡単に復元する6つの方法|データ復元
Windows 10、Windows 11の付箋を簡単に復元する6つの方法|データ復元Windows 10、Windows 11の付箋を簡単に復元する6つの方法|データ復元
Windows 10、Windows 11の付箋を簡単に復元する6つの方法|データ復元ivanwang53
 
ダウンロードがダウンロード(Downloads)フォルダに表示されない」問題の対処法
ダウンロードがダウンロード(Downloads)フォルダに表示されない」問題の対処法ダウンロードがダウンロード(Downloads)フォルダに表示されない」問題の対処法
ダウンロードがダウンロード(Downloads)フォルダに表示されない」問題の対処法ivanwang53
 
Windows Defenderのフル・クイック・カスタム・オフラインスキャンを実行する方法.docx
Windows Defenderのフル・クイック・カスタム・オフラインスキャンを実行する方法.docxWindows Defenderのフル・クイック・カスタム・オフラインスキャンを実行する方法.docx
Windows Defenderのフル・クイック・カスタム・オフラインスキャンを実行する方法.docxivanwang53
 
あらゆる通信環境で切れない「ネットモーション」のモバイルアクセス [NetMotion]
あらゆる通信環境で切れない「ネットモーション」のモバイルアクセス [NetMotion]あらゆる通信環境で切れない「ネットモーション」のモバイルアクセス [NetMotion]
あらゆる通信環境で切れない「ネットモーション」のモバイルアクセス [NetMotion]Taka Narita
 
Windowsアップデート後の黒い画面を修正する方法|データ復元|ブラックスクリーン
Windowsアップデート後の黒い画面を修正する方法|データ復元|ブラックスクリーンWindowsアップデート後の黒い画面を修正する方法|データ復元|ブラックスクリーン
Windowsアップデート後の黒い画面を修正する方法|データ復元|ブラックスクリーンivanwang53
 

Recently uploaded (6)

動的 & 非同期コンポーネント / Dynamic & Async Components
動的 & 非同期コンポーネント / Dynamic & Async Components動的 & 非同期コンポーネント / Dynamic & Async Components
動的 & 非同期コンポーネント / Dynamic & Async Components
 
Windows 10、Windows 11の付箋を簡単に復元する6つの方法|データ復元
Windows 10、Windows 11の付箋を簡単に復元する6つの方法|データ復元Windows 10、Windows 11の付箋を簡単に復元する6つの方法|データ復元
Windows 10、Windows 11の付箋を簡単に復元する6つの方法|データ復元
 
ダウンロードがダウンロード(Downloads)フォルダに表示されない」問題の対処法
ダウンロードがダウンロード(Downloads)フォルダに表示されない」問題の対処法ダウンロードがダウンロード(Downloads)フォルダに表示されない」問題の対処法
ダウンロードがダウンロード(Downloads)フォルダに表示されない」問題の対処法
 
Windows Defenderのフル・クイック・カスタム・オフラインスキャンを実行する方法.docx
Windows Defenderのフル・クイック・カスタム・オフラインスキャンを実行する方法.docxWindows Defenderのフル・クイック・カスタム・オフラインスキャンを実行する方法.docx
Windows Defenderのフル・クイック・カスタム・オフラインスキャンを実行する方法.docx
 
あらゆる通信環境で切れない「ネットモーション」のモバイルアクセス [NetMotion]
あらゆる通信環境で切れない「ネットモーション」のモバイルアクセス [NetMotion]あらゆる通信環境で切れない「ネットモーション」のモバイルアクセス [NetMotion]
あらゆる通信環境で切れない「ネットモーション」のモバイルアクセス [NetMotion]
 
Windowsアップデート後の黒い画面を修正する方法|データ復元|ブラックスクリーン
Windowsアップデート後の黒い画面を修正する方法|データ復元|ブラックスクリーンWindowsアップデート後の黒い画面を修正する方法|データ復元|ブラックスクリーン
Windowsアップデート後の黒い画面を修正する方法|データ復元|ブラックスクリーン
 

Go conference 2021 autumn

Editor's Notes

  1. 自己紹介です。私は伊藤真彦と申します。フューチャー株式会社という会社で、ITコンサルタントとして働いています。担当領域は要件定義から実装まで全てです。今年はAWSの資格を取ることに力を入れていました、気持ちよく自己紹介するために先週11個すべてを取得しました。
  2. 会社の説明もさせていただきます。フューチャーはITコンサルティングを中心に、開発、保守までを一気通貫の体制で行う会社です。Go Conferenceのブロンズスポンサーをやっています。本日は私を含め3名の社員が登壇しています。
  3. 発表のモチベーションですが、皆さんはGoでいうとポインタやインターフェースなど、熟知しているとはいえないものの使えている機能に心当たりは無いでしょうか。私にとってはContextもそのうちの一つでした、抽象化されたインターフェースがある事は素晴らしい事ですが、そういったものを一度立ち止まって深く理解する機会を設けたいなと思い、発表のテーマに選びました。また、今回の発表はcontextの内部実装を追う事で知らなかった、忘れていた、というGoのテクニックを学べるものになるように意識しています。
  4. それでは、Contextの概要から説明します。
  5. contextはAPIの境界を越えて、プロセス間で、期限、キャンセルシグナル、 およびその他のリクエストスコープの値を伝達します、と公式の説明に記載されています。平たく言うと、採用したライブラリがContextを提供してくれたり、DBクライアントライブラリなどがcontextを受け取る機能を用意している場合があります。 そこでcontextをバケツリレーのように渡していくだけでタイムアウトやキャンセルが適宜制御される、といったものです。
  6. 例えば、AWS Lambdaの上で動くコードを書く際に利用するライブラリを利用すると、エントリポイントとなる関数のlambda.Startに渡す任意の実装がcontextを受け取るようになっています。 また、DynamoDBに接続するためのクライアントライブラリはcontextを受け取り、contextに設定されたタイムアウト時間を過ぎるとDBへのアクセスを中断できる関数が存在します。
  7. もちろん任意の実装も可能です、ここで書いている処理は、context.WithTimeout関数で作ったcontextに対して設定した時間、処理を繰り返すコードになっています。 コードを読んでみます、5秒後にタイムアウトする設定をしたcontextの変数を作成して、execute関数に渡しています、execute関数では無限ループを行っていますが、select文でcontextのタイムアウトを監視し、タイムアウトした場合は処理を終了するように実装しています、処理は一秒間待機してExecute Somethingという文字列を吐いているだけですが、実行結果のように5秒間処理を繰り返したあとに停止しています。
  8. より実用的な例として、Go1.16から採用されたsignal.NotifyContext()を用いたgracefulシャットダウンを紹介します。gracefulシャットダウンとはつまりユーザーがプロセスをキルしても安全に停止できる処理ですね。これは渋川さんがフューチャー技術ブログに書いています。
  9. このように、contextには様々な使い方が存在しますが、最近zennにわかりやすい書籍が公開されました。目次の通り、contextがもっている機能とその使い方が説明されています。これを読めば基本的な使い方はマスターできます。
  10. なぜ質の高い情報があるのに発表するのか、という言い訳なんですが、私がcontextをテーマに登壇するプロポーザルを提出してから先ほどの書籍が公開されました。そしてわざわざ撤回するべきかと迷っている間に採択された形です。正直焦りました。
  11. しかし、この本のお陰で私の発表は内部実装にフォーカスしたものにすることができます、ありがとうございます。
  12. というわけで、次のセクションからは内部実装を深堀していきます
  13. Contextは発表段階で593行ですべてが実装されています。 そのくらいの量であれば今日の発表で全部コードリーディングできるだろう、というのが発表の趣旨です
  14. 頭からコードを読む前にcontextとは、という話をします contextの実態はinterfaceです、Deadline Done Err Valueの4つのインターフェース使用を満たしたcontext構造体がいくつか存在し、外部からはそれらを抽象化して利用しています
  15. 序盤はコメントが多いので、これだけで154行まで説明が済みます
  16. 次に、キャンセル、タイムアウト時に所定のメッセージを返すためのエラーが2種類定義されています。Canceldはシンプルなエラーです DeadlineExceededは通常のエラーより拡張された独自のエラー型です、拡張機能として実装されたTimeout, Temporaryは内部では利用されていません これらはnetパッケージで提供されているエラーと同じインターフェース使用を満たすことで、呼び出し元でのリトライ制御に役立てることができます
  17. 参考までにnetパッケージのErrorインターフェースを見てみましょう、左上の画像の通り、素朴なerrorに加えtimeout, Temporaryが拡張されたインターフェースが実装されています。このインターフェース仕様を満たす独自の構造体errNetClosingなどがnetパッケージには存在します。context内部の独自エラーはこの作法に則っています。使い方は右側の画像の通り、型アサーションでnet.Errorインターフェースの仕様を満たすかを確認してからTemporaryメソッドを呼び出して、リトライやログレベルの分岐などの制御が行えます。
  18. contextの話に戻りますが、エラーなど定数的な情報の記述が終わったら、最も素朴なemptyCtxが定義されています。emptyCtxはintがベースとなった型です。この型の変数が全て異なるアドレスを持つために、structではなくintから型を定義しているとコメントに書いてあります、詳しくは後で説明します。 emptyCtxはInterface仕様を満たすための関数を備えています。いずれもnilやfalseのような値を返すものが多いです。Deadline関数では、名前付きの戻り値を使う事でreturn文をシンプルに書いたままtime.Timeとboolの0値を返却する、というトリッキーな書き方になっています。この手法を業務で上手く使う人は少ないと思いますので、テクニックとして覚えておきたいですね。Stringだけはbackgroundとtodoを区別するためのswitch文が書かれています。
  19. Background, todoは内部で変数定義されています、この二つのemptyCtxを外部から取得する Background, TODOが定義されています。一見するとbackgroundとtodoはStringメソッドの処理の分岐結果以外に違いがありません。実際持っている機能としては完全に同じで、後続処理でもこの二つを区別していません。コメントを読んでみると、可読性のためにわけられている事がわかります。context.Backgroundは、これから設定を詰めるための初期化のために取得するcontextです。一方todoは用途が明確でない、もしくは必要か明確に定まっていないときに一時的に置いておくものとして呼び出します。意義としての使い分けはされていますが、backgroundを使って欲しいタイミングでtodoを呼び出してもバグが起きることはありません
  20. 値のすべてが異なるアドレスを持つ、とはどういう事なのかは、実際に動かしてみるとわかります。intを基にした型とstructを基にした型を用意し、その方の変数を複数作ります。これらは同じ型なので==で比較できますが、intを基にした型は一つ一つの変数を宣言するたびに新しくメモリを確保し、違うアドレスが割り当てられますが、空のstructを基に型を作ると、同じデータが使いまわされ、メモリが節約されます。この挙動の違いがあるため、emptyCtxがstructで作られた場合はbackgroundとtodoを比較するとtrueになります。これを回避するためにemptyCtxはintを拡張したものとして作られています。
  21. emptyCtxは以上です、続いてcancelCtxの実装が始まります、cancelCtxはその名の通り処理のキャンセル機能を作るうえで役立つ実装が組み込まれたcontextです、WithCancel関数でcancelCtxと、それをキャンセルするための関数を取得できます。emptyCtx以外はWith~の関数で呼び出すときに親のコンテキストを渡して、親子関係をネストする仕組みが作られています。
  22. 245行目あたりから、親子関係としてネストしているコンテキストのキャンセル情報を伝播させるための関数が実装されています。言葉にするとシンプルですがcontextパッケージの中では読み解くのが難しい部類です。
  23. propagateCancel内部で呼び出されているparentCancelCtxで、親コンテキストの状態、型を確認しながら、キャンセル状況を伝播させるための関係性を整理しています、コメントを読んでみても割と内容が伝わりづらいです。
  24. 314行目でremoveChildが実装されています、その名の通り、cancelCtxに登録されたchildrenを掃除するための処理です
  25. 326行目でcanceleインターフェースが定義されています、これはcancelCtxと、このあと紹介するtimerCtxがこの仕様を満たします。
  26. 333行目でclosedchanとcancelCtxが定義されています、closedchanはその名の通りinitで即閉じられるチャネルです。 cancelCtxがキャンセルされているか否かはチャンネルの状態で判断しています。
  27. 351行目から、Value Done Errが定義され、contextのインターフェース仕様を満たしています。cancelCtxは並行処理で動作する事を見越して作られているので、読み込むと並行処理の勉強になります。
  28. 380行目~ String()とそれで用いる関数が定義されています StringはinterfaceとしてのContextに定義されていないため、直接呼び出すことはできません
  29. 試してみると画像のようになります、画像右のようにstringerインターフェースを定義して型アサーションする事で無理やり呼び出すことは可能です。
  30. ややこしい事をしなくても、fmtパッケージのPrint関数に渡すことで同じことができます。
  31. 397行目から、cancelが実装されています。これはcontext.WithCance関数lで取得できるキャンセル機能です。これを実行するとcancelContextの持っているチャンネルがcloseされます。同時に親子関係を参照し、キャンセル状況を伝播させるべきcontextもキャンセルします。
  32. cancelCtxについては以上です。425行目から、WithDeadLine関数が実装されています。この関数には親のcontextとデッドラインとなる時刻を引数で渡します。親のコンテキストが既にタイムアウト済であったり、与えたデッドラインが過去の時間だった場合の保険も実装されていますが、デッドラインの時刻でキャンセルが呼び出されるように予約されたtimerCtxと、それを任意のタイミングでキャンセルする関数が返却されます。
  33. ここで使われているtime.AfterFuncは、処理を遅延実行させることが簡単に行える便利な機能です、覚えておくと予約実行機能を実装したい時に役に立ちます。
  34. 465行目にtimerCtxが定義されています。cancelCtxがフィールドに埋め込まれており、timerCtxはcancelCtxの拡張であることがわかります。cancelCtxに、キャンセルの予約実行機能と、デッドライン時刻の返却機能をもたせたものがtimerCtxという事になります。
  35. func (t *timerCtx) Done()のような記述は一切ありませんが、構造体の埋め込みによりtimerCtxはcancelerのインターフェース仕様を満たしています,Goはこのように埋め込んだ構造体、インターフェースが持っている関数を直接呼び出すことができます。
  36. 一方cancelは埋め込んだcancelCtxのcancelを呼び出しつつ、 タイマーを掃除するtimerCtx独自のものが実装されています
  37. 472行目〜 DeadLine()が実装されています emptyCtxと比較すると0値でない値が取得できていることがわかります cancelCtxは独自のDeadline関数を持たず、埋め込まれた親コンテキストのDeadlineを呼んでいます
  38. 476行目から、timerCtxのString関数が実装されています。思ったより素朴に文字列が+演算子で結合されています。
  39. 496行目からWithTimeout関数が実装されています。実装を見てみると、WithDeadLineのラッパー関数である事がわかります。
  40. timerCtxについては以上です、続いて最後のcontextであるvalueCtxの説明に入ります。510行目からWithValue関数が定義されています。親コンテキストと、key, valueを受け取り、任意の値をもったvalueCtxを返却します。
  41. valueCtxは親Contextとkey, valを持った比較的シンプルな構造体です、keyもvalも空のinterfaceです
  42. valueCtxも独自のString()関数を持っています 敢えてfmtパッケージには依存せずに独自のstringify関数をもっています、unicode tablesに依存したくないとコメントがありますが、話が高度すぎて意図を完璧に理解できているか自信がありませんが。
  43. 実際にシンプルなコードで試してみましたが、fmtパッケージをインポートするとビルド結果が800KBほど大きくなりました
  44. ともかくこれで全てのcontextのString関数を読み込みました、ここで大事な事は、contextはプリントデバッグすると持っている情報を全て吐き出すという事です。一緒に働いている辻さんがブログにしてくれたのですが、GoのコードでLambdaを呼び出すときに、Contextに詰めた値を取り出そうとして取り出せず混乱した経験があります
  45. どういう事かというと、クライアント側でAWS Lambdaを起動するために呼び出す関数にcontextを渡すことができるのですが、そのcontextに詰めたValueがLambda上で動くコードでは消滅するのが仕様なのか否かを判断するのにそこそこ時間を使って調査したことがありました。 情報がプリントデバッグして無いなら無いんだ、と自信をもって判断して良い、という事が発表から伝われば幸いです。
  46. さてcontextの実装の話に戻ります、562行目から、valueCtxの目玉機能のValue関数が実装されています、keyが一致したらvalを返すという、シンプルな実装ですね
  47. Valueに渡す値は==で一致するものであればなんでも良いですがcontextパッケージの内部実装ではint型の変数を○○keyの名称で用意して、そのポインタ型を利用する使い方が良く使われています。おそらくメモリ効率を考えるとこの手法が一番スマートです。
  48. ポインタ型を投げなくてももちろん動きます。文字列などでラフに値を取り出したいかkeyの重複を考慮せずに済む方が良いかで使い分けできます
  49. 最後に内部で呼び出されるvalue関数の実装をもって593行が終了です、keyがヒットするかemptyCtxにたどり着くまで無限に各context型のValueとほぼ同じことをします 再帰関数になりそうでならない実装です
  50. さて、これでcontextのコードリーディングは終了です、駆け足でしたが、これを読み込むことで何が勉強になるかを整理してみます。