Goの並行処理は、書けるようになるまでが長く、いったん慣れても「この場面では channel でよかったか、mutex か、select か」と迷いがちです。今回の「Go concurrency distilled」は、その迷いをほどくための短い再整理版として公開されました。しかも単なる解説ではなく、コードをその場で動かしながら試せる作りです。Goで仕事をしている人にとっては、基礎の学習書というより、手元の知識を整えるための速い復習帳に近い内容です。
元記事は、Anton Zhiyanov氏が公開した「Go concurrency distilled」というミニブックの紹介です。扱うのはGoの並行処理で、goroutines、channels、select、pipelines、time、context、wait groups、data races、race conditions、mutexes、semaphores、signaling、run once、object pool、atomics、testing、scheduling、diagnostics、final thoughts といった話題が並びます。各トピックにはインタラクティブな例が付いていて、コードを変更して Run を押しながら挙動を確かめられるのが売りです。静的な例だけを集めたPDF版もあります。
著者は、これは「Goの並行処理をゼロから教える入門書ではない」とはっきり書いています。あくまで、すでに一度学んだ人が要点を素早く思い出すための短い本だという位置づけです。もし基礎から実践課題つきで学びたいなら、別の本「Gist of Go: Concurrency」を案内しています。しかもこの本は「AI-free」とも明記されています。
内容そのものは、Goの並行処理で頻出する部品を順にほどいていく構成です。まず goroutines では、go キーワードで関数を別 goroutine として起動し、sync.WaitGroup で終了を待つ基本を押さえます。WaitGroup は内部カウンタを持ち、Add で増え、Done で減り、Wait でゼロになるまで止まります。さらに WaitGroup.Go という、カウンタ増減と起動をまとめて扱う形も紹介されています。
channels の章では、goroutine 間で値を受け渡す仕組みを説明します。送信は同期的で、受信側が受け取るまで送信側は止まります。出力用の channel を関数から返して内部 goroutine で埋める定番パターンや、close() で「もう送るものがない」と知らせる方法、受信側が value, ok := <-ch で閉じたかどうかを見るやり方も出てきます。range で channel を回せば、閉じられた時点でループが終わります。方向付き channel、つまり送信専用 chan<- と受信専用 <-chan も扱い、誤った操作を防ぐ考え方を示します。バッファ付き channel は固定長の FIFO キューのように振る舞い、バッファが空いていれば送信が詰まらず、値が入っていれば受信が詰まらない、という違いを見せます。逆に nil channel は送受信が永久にブロックし、閉じると panic になります。
select の章は、channel 用の switch のようなものとして説明されています。複数の受信先をまとめる merge、cancel channel を使った中断、default を使う非ブロッキング送信など、実際の制御にどう使うかが中心です。そこから pipelines に進み、読み込み、変換、書き込みを channel でつないだ処理の流れを描きます。加えて、完了通知用の done channel、途中終了のための cancel channel、そしてエラー処理の複数のやり方にも触れています。本文は途中で省略されていますが、少なくとも「並行処理の部品を、用途別に使い分ける」という筋道を作っていることは分かります。
面白いのは、著者が最初から「入門」ではないと割り切っている点です。Go の concurrency は、概念自体は難解というより、部品が多くて使い分けが面倒です。goroutine と channel だけ覚えても、閉じるタイミング、キャンセル、バッファサイズ、select の default、WaitGroup の責務分離がすぐに混ざる。だから、こういう再整理型の本は、初学者よりも「一度書いたことがある人」に効くと思います。頭の中で散っていた知識が、部品ごとの役割として戻ってくるからです。
インタラクティブ例は、Go の並行処理とかなり相性がいいです。というのも、この分野は説明文を読んだだけでは誤解しやすいからです。たとえば channel は「送ったらすぐ流れる箱」みたいに思われがちですが、実際は同期点でもあります。バッファ付き channel も、数個までは止まらないというだけで、無限に捌けるわけではありません。こうした挙動は、文章だけよりコードを動かしたほうが腹落ちしやすい。著者がそこに寄せたのは自然ですし、Go という言語の教育素材としてはかなり相性がいいやり方だと思います。
Go では並行処理が書きやすいぶん、雑にも書けます。close の責任をあいまいにしたまま channel を共有したり、nil channel を条件分岐の都合で置いてしまったり、select の default で忙しく回してしまったり。ミニブックであっても、そういう落とし穴を一つずつ見せる価値は大きいです。特に data races や race conditions、mutexes、atomics まで視野に入れているのは、単に「channel で何とかする」話で終わらせない姿勢として好感が持てます。Go の並行処理は美しいというより、事故を避ける規律が要る。そこを短い本で整理するのは、かなり実務向きです。
本文には、この本が AI-free だとはっきりあります。これは単なる売り文句にも見えますが、今の文脈では少し意味があるとも思います。並行処理の説明は、表面的にはもっともらしく見せやすい一方で、細部を外すと途端に危うい。channel の閉じ方、select の分岐、ブロック条件は、うろ覚えの文章だとすぐ崩れます。だから、手で書かれた教材であることを前面に出すのは、品質への自信表明として読めます。とはいえ本当に大事なのは AI を使ったかどうかより、例が正確で、読者が手を動かしたときにズレないことです。そこに著者がどこまで責任を持っているかが、この種の教材では一番大切だと思います。