$shibayu36->blog;

クラスター株式会社のソフトウェアエンジニアです。エンジニアリングや読書などについて書いています。

golangのcontextのcancel伝播の仕組みを学ぶために自作してみた

並行プログラミングを学ぶ一環で、「Contextを完全に理解する」というテーマでGo Conference 2021 Autumnに登壇しました の記事を見つけ、contextのcancel伝播の実装方法が気になった。そこで自分でcontextのcancel部分だけを自作することで伝播の理解を深めてみた。

実装はこちらで、context.WithCancel的なものとcontext.WithDeadline的なものを実装している。またテストコードも用意している。

実装してみて面白いなと思ったのは、contextの実装は可能な限りgoroutineを起動しないようにうまく実装されているということ。

自作する前にgolangのcontextの実装を眺めていたが、最初はこの辺りを見て、子の側でgoroutineを起動して親のDone()を見ているのだなと思い込んでいた。しかし実際には、

  • 親となるcontextが全ての子を管理して親から子にcancelを伝えていくパターンである場合は、goroutineを起動せずに親に任せるというやり方を取っている。これにより無駄なgoroutineを起動する必要がない
    • この辺りでparentCancelCtxを見たり、afterFuncerかを見たりして、早期returnすることでgoroutineを起動しないようになっている
  • 親がそのようなパターンではない場合は、goroutineを起動して待つようにする。これによって独自にContext interfaceを実装しているケースでもうまくcancelを伝播させることができる

ということを知った。

なるほどと思ったので、cancel部分の自作バージョンでも以下のようにgoroutineを起動しないような仕組みになるように実装してみた。

標準のcontextはよく出来ていると実感した。また理解するには自作してみるのが一番深掘りできて良い。