16.5 ゴルーチン間のイベント伝達

チャネルはゴルーチンセーフなデータ構造で、送信元から受信先へ「データ」を伝達します。しかし、何かしらのデータではなく「何かが発生した」というイベントだけを通知したいことがあります。たとえばタスクが完了したという通知などです。Goのライブラリでは、サイズゼロの空の構造体を使ったチャネルがよく利用されています。

	// ゼロバイトの構造体のチャネル
	wait := make(chan struct{})

	// 受信
	<-wait

このチャネルを使って通知する場合には、空の構造体のインスタンスを送ります。

	// 送信
	wait <- struct{}{}

上記のようにイベントを送信すると、イベントを受信する複数のゴルーチンのうち、1つだけがイベントを受け取れます。複数のチャネルへイベントをブロードキャストしたい、かつそのイベントが1度だけ発生する場合には、チャネルをクローズする方法があります。

	// 送信の代わりにクローズ
	close(wait)

チャネルをクローズすると、同じチャネルを監視しているすべてのゴルーチンへ一斉に通知が行きます。これはイベントをブロードキャストしているのと同じ効果があります。一度クローズしたあと、そのチャネルへ再度読み込みに行こうとするとブロックせずにゼロ値が返ります。

チャネルの送信を用いて通知を行うと、1つの相手に1件のみ厳密に伝わります。相手が見えているのであればチャネルの送信でも良いですが、ささいなミスでブロッキングし続けることもあるため、クローズの方が安心です。

チャネルは誰も参照しなくなれば、クローズしなくてもガベージコレクタに回収されますが、たとえば、どこかのゴルーチンで読み込みを続けていると、それがブロックされ続けて、チャネルリークの原因となります。 ...