少し前に、レビューに参加したGo言語による並行処理が出版されました。献本もいただきました。ありがとうございました。レビューする前から、かなり読みやすい翻訳となっており、3章分レビューして欲しいと、作業分担はあったのですが、おもしろくて全部読んでしまいました。より詳しい本書の内容はmattnさんのブログが詳しいので、そちらを読んでいただくのが良いと思います。
謝辞にも書いていただいたのですが、僕もGoならわかるシステムプログラミングで並行とか並列とか書いたことがあったので、注釈として原著の内容を補足して増やしてもらう方向のコメントを少ししたりしました。Goでの並行処理を学ぶには最上の一冊としてあって欲しいですからね。僕の本はどちらかというと、「Goを学ぶ」よりも「Goで学ぶ」志向ですし。また、翻訳の指摘というよりかは「きっと著者が本来言いたかったことはこうだ」と、原文で気になったところとかも多少コメントしました。
僕のレビューの貢献はごく一部ですが、ymotongpooの献身的なコミットメントや、多くの人達のすばらしい指摘により、英語ができる人が英語で原文を読むよりも、遥かにすばらしい翻訳になっています。最新の1.11での結果以外にも、いくつも日本語オリジナルのコラムがあります。英語版を買った人も、ぜひ日本語版を手にとって見てください。
context
本書でも、contextに関しては4.12で説明されています。Goの設計について議論になると高確率で指摘が飛んでくるのが例外処理ですが、contextはかなりGoっぽい例外処理機構だな、と改めて思いました。例外処理機構としてのcontextについては、Pull Requestのプロポーザルでも触れられていないので、こういうことを考えている人は少ないのかな、という気持ちもあるのでこのエントリーの中でちょっと説明してみようかと思います。
例外処理というのは、よくある言語の機能としては、問題が起きたときにそれを上流に流す機能です。あまり見かけない機能としては、Rubyのretryによる再実行とかがありますね。最近話題のReactのSuspenseは、ただ上流に流すだけではなく、完了時に再実行するためのPromiseを投げる機能が追加されています。で、golangはというと他の言語にある例外はありませんが、contextが一種の例外処理を担っていると言えると思います。
Goは本書の帯のように「湯水のように」並行処理が行えます。例外は現在実行されているスレッドのスタックを巻き戻しながら、帯域脱出します。しかし、Goのように複数のgoroutineがあると、現在のスタックのみを巻き戻しても仕方がありません。contextは、sync.Condのような条件変数として動作します。起点となるgroutineから、100個のgroutineが起動したとしても、context一つで、一斉にタスクを止めることができます。正確には、各groutineがcontextを見て、任意のタイミングで処理を中断します。
GoはgoroutineがIDを持っておらず、そのために外部から強制的に中断させることはできません。しかし、中断しても良い切のいいところにいるかどうかは外部からはわからないため、合理的な設計になっていると言えます。contextの一斉停止のトリガーも、ネットワークを使うシステムでよく使われるGoらしく、自発的なキャンセル以外にも、タイムアウトなどが用意されています。このあたり、他の言語でも少し欲しくなってきます。
Go 2のproposalの中にはエラーハンドリングについてのものもありましたが、個人的には、JavaScriptやC#などのasync関数のように、contextを扱う関数をより実装しやすくする、という方が、エラーハンドリングの根本解決になるのではないか、と思ったり・・・
話はそれましたが
Go言語による並行処理はおすすめです!6月に出たGo言語で作るインタプリタ本も良かったですし、プログラミング言語別の年収ランキング中央値1位になったGoを簡単に深く学べる環境がどんどん整ってきています。