package main
import (
"fmt"
"sync"
)
// producer関数は整数チャンネルに整数を送信します。
func producer(ch chan int, i int) {
// チャンネルにi * 2を送信
ch <- i * 2
}
// consumer関数はチャンネルから受信した整数を処理し、WaitGroupのDoneメソッドを呼び出してカウントを減らします。
func consumer(ch chan int, wg *sync.WaitGroup) {
// チャンネルから受信した整数を処理
for i := range ch {
fmt.Println("process", i*1000)
wg.Done()
}
}
func main() {
// WaitGroupを初期化
var wg sync.WaitGroup
// 整数チャンネルを作成
ch := make(chan int)
// 10個のプロデューサーゴルーチンを起動
for i := 0; i < 10; i++ {
wg.Add(1)
go producer(ch, i)
}
// コンシューマーゴルーチンを起動
go consumer(ch, &wg)
// すべてのプロデューサーが終了するまで待機
wg.Wait()
// チャンネルを閉じる
close(ch)
}
プログラムの流れ
-
WaitGroupの初期化
var wg sync.WaitGroup
sync.WaitGroup
を使って、複数のゴルーチンの終了を待つためのカウンタを作成します。 -
チャンネルの作成
ch := make(chan int)
整数を送受信するためのチャンネルを作成します。
-
プロデューサーゴルーチンの起動
for i := 0; i < 10; i++ { wg.Add(1) go producer(ch, i) }
10個のプロデューサーゴルーチンを起動します。各ゴルーチンは
producer
関数を実行し、i * 2
の値をチャンネルに送信します。 -
コンシューマーゴルーチンの起動
go consumer(ch, &wg)
1つのコンシューマーゴルーチンを起動します。
consumer
関数はチャンネルから整数を受信し、それを処理します。 -
プロデューサーの終了待機
wg.Wait()
すべてのプロデューサーゴルーチンが終了するのを待ちます。
-
チャンネルのクローズ
close(ch)
チャンネルを閉じます。これにより、
consumer
関数のrange
ループが終了します。
出力の詳細
各プロデューサーゴルーチンは、以下のようにi * 2
の値をチャンネルに送信します:
-
i = 0
の場合、送信値は0 * 2 = 0
-
i = 1
の場合、送信値は1 * 2 = 2
-
i = 2
の場合、送信値は2 * 2 = 4
...
-
i = 9
の場合、送信値は9 * 2 = 18
コンシューマーゴルーチンは、これらの値を受信し、i * 1000
を計算して表示します。したがって、出力は以下のようになります:
0 * 1000 = 0
2 * 1000 = 2000
4 * 1000 = 4000
...
18 * 1000 = 18000
出力順はゴルーチンの実行順によるため、必ずしも順番通り(0, 2, 4, ... 18)にはなりませんが、出力される値は以下となる。
process 0
process 2000
process 4000
process 6000
process 8000
process 10000
process 12000
process 14000
process 16000
process 18000
注意点
- プログラムは、プロデューサーが
ch
に値を送信した後すぐにDone
を呼び出しているため、wg.Wait
が終了した時点でch
にまだ値が残っている可能性があり、close(ch)
が早すぎる問題があります。 -
consumer
側でwg.Done
を呼び出すべきでなく、プロデューサー側で呼び出すべきです。また、ch
を閉じるタイミングも見直す必要があります。