Go言語での複数チャネルからのメッセージ受信

Goではgoroutineを使うことで並行処理をとても簡単に実行できるが、複数goroutineとの同期が難しい。
そこで、複数走らせたgoroutineのメッセージを用いた同期方法について考えてみた。

以下のように、複数のチャネルからのメッセージを受信する必要がある時、どうやって各goroutineからのメッセージを、同時に、最後まで、受信すればいいか?

func f(msg string, n int) chan string {
    ch := make(chan string)
    go func() {
        for i:=0; i<n; i++ {
            ch <- msg + " please!"
        }
        close(ch)
    }()
    return ch
}

func main() {
    ch1 := f("beer",  4)
    ch2 := f("juice", 2)
    ch3 := f("water", 1)

    // ここでch1, ch2, ch3のメッセージを受信したい
    // それぞれのchannelは非同期に動いていて
    // 終了までに送られてくるメッセージ数も異なる
    …

    fmt.Println("exit")
}


selectによる複数メッセージ受信

selectを使って複数チャネルからのメッセージ受信を同時に行う。
チャネル通信の完了は、完了通知用のチャネルを生成して通知する。
Go Playgourndで実行


受信部分をgoroutine化して複数メッセージを非同期受信

メッセージの受信処理を無名関数でラッピングして、チャネル毎にgoroutine化して実行。
range節でチャネル受信をループ化しているため、チャネルがcloseされるとループが終了する。
main関数での受信完了同期にはWaitGroupを使っている。
Go Playgourndで実行


受信部分をgoroutine化する方法は、main関数でメッセージを受け取ってない。
reporterからmainに処理結果を渡さなくちゃいけないときには別途チャネルが必要になるけれども、メッセージの値を表示させるだけならコードがシンプルになっていい。

追記

以下のようにWaitGroup.Wait()をgoroutine化して待つ方法もある。

参考