本文へスキップ
BecomeCoder

Goコース · 第6章 並行処理 · レッスン23

複数の goroutine を待つ ― WaitGroup

ブラウザで完結

導入

たくさんの 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 なら「全部終わった」ことを確実に待てます。実務での定番です。

やってみよう

ループ変数 igo func(n int){...}(i) のように引数で渡している点に注目しましょう。こうしないと、goroutine が動くころには i が進んでしまい、意図しない値を参照することがあります。

実際に動かしてみよう

下のエディタにGoを書いて「実行」を押すと、学習用シミュレータが fmt の出力を表示します(本物のGoコンパイラではなく、教材の範囲を再現した軽量エンジンです)。スライス・マップ・構造体・インターフェース・goroutine/channel なども動きます。本文の例を書き換えて動かしてみましょう(並行処理の実行順は決定的に再現しているため、本物のインターリーブとは異なる場合があります)。

Go — ブラウザ内で実行(学習用シミュレータ)

Goの教材サブセットを動かす学習用シミュレータを読み込みます(本物のGoコンパイラではなく、動きを再現した軽量な自作エンジンです)。
スクロールして表示された時点でも自動で読み込まれます。