導入
たくさんの goroutine を起動して、「全部終わったら次へ進みたい」場面はよくあります。その待ち合わせをきちんと行う道具が sync.WaitGroup です。
説明
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1) // 待つ対象を1つ増やす
go func(n int) {
defer wg.Done() // 終わったら1つ減らす
fmt.Println("worker", n, "完了")
}(i)
}
wg.Wait() // すべて Done になるまで待つ
fmt.Println("全員終了")
}
wg.Add(1)… これから待つ goroutine を1つ登録。defer wg.Done()… その goroutine が終わるとき、カウントを1減らす(deferで確実に)。wg.Wait()… 登録した数がすべてDoneになるまで待ちます。
Sleep で「たぶん終わっただろう」と待つのではなく、WaitGroup なら「全部終わった」ことを確実に待てます。実務での定番です。
やってみよう
ループ変数 i を go func(n int){...}(i) のように引数で渡している点に注目しましょう。こうしないと、goroutine が動くころには i が進んでしまい、意図しない値を参照することがあります。