チャネルでGoの並行処理をマスターする
かつて、私はGoで画像処理パイプラインを構築したことがあります。
すべてのステップにgoroutineを使用し、それらをチャネルで繋ぎました。そして、実行ボタンを押しました。
プログラムはフリーズしました。メモリ使用量は上昇し、そして死にました。エラーは出ませんでした。ただ、静寂だけがありました。
壊れたスケジューラをデバッグするために何時間も無駄にしました。間違っていたのは私でした。チャネルの仕組みを理解していなかったのです。
Goプログラムがハングするのを防ぐための3つのルールを紹介します。
- Nilチャネルはブラックホールである Nilチャネルは永遠にブロックされます。Nilチャネルに対して送信または受信を行うと、goroutineは停止したままになります。
- 必ず
makeでチャネルを初期化してください。 - 不確かな場合はNilチェックを行ってください。
- クローズのルールを守ってパニックを防ぐ チャネルのクローズは不可逆的です。
- チャネルをクローズするのは送信者のみにすべきです。
- クローズ済みのチャネルにデータを送信すると、パニックが発生します。
- チャネルがクローズされているか確認するには、第2戻り値を使用します:
v, ok := <-ch。 okがfalseであれば、チャネルはクローズされています。
- 安全性のためにチャネルの方向を指定する Goでは、チャネルが送信用か受信用かを指定できます。
chan<- intは、データの送信のみが可能であることを意味します。<-chan intは、データの受信のみが可能であることを意味します。- これにより、コードを実行する前にコンパイラがミスを検知できるようになります。
クリーンなパイプラインを構築する方法:
defer closeを使用して、チャネルが確実に一度だけクローズされるようにします。- チャネルのループには
rangeを使用します。これにより、チャネルがクローズされると自動的に停止します。 - 関数に方向を指定した型を割り当て、厳格な契約(コントラクト)を作成します。
これらのパターンに従うことで、リークやパニックを防ぐことができます。テストが容易で、堅牢なシステムを構築できるようになります。
あなたへの挑戦:
複数の入力チャネルを1つの出力チャネルにマージする関数を書いてください。select ループを使用し、500msのタイムアウトを追加してください。また、goroutineがリークしないことを保証してください。
あなたの解答をコメント欄に投稿してください。