コース一覧
    Go実践:並行処理とWeb API
    待ち合わせ

    Go実践:並行処理とWeb API

    Goの並行処理とWeb API開発を組み合わせ、実践的なサービス構築へ進むコースです。

    1
    ゴルーチンと並行処理のさわり
    01. ゴルーチン15分
    02. チャネル20分
    03. 待ち合わせ20分
    04. 並行の落とし穴20分
    05. つくる: 並行集計20分
    06. 第7章クイズ10分
    2
    Web API(net/http)
    01. サーバーを立てる20分
    02. ハンドラ関数20分
    03. JSONを返す20分
    04. ルーティング20分
    05. 一覧API20分
    06. 詳細APIと40420分
    07. 出品API20分
    08. つくる: API主要部完成25分
    09. 第8章クイズ10分
    3
    総合制作
    01. 仕様互換を仕上げる25分
    02. Node版と差し替える25分
    03. 1バイナリでデプロイ25分
    04. 自由拡張25分
    05. 完成と次のステップ20分

    待ち合わせ

    数を数えずに待つ

    チャネルで待つには、入れた数と取り出す数を合わせる必要がありました。処理が増えると、この数合わせが面倒になります。

    sync.WaitGroup は、数を数える係を用意してくれます。

    Go

    import "sync"
    
    var wg sync.WaitGroup
    
    for _, item := range items {
    	wg.Add(1)
    	go func() {
    		defer wg.Done()
    		process(item)
    	}()
    }
    
    wg.Wait()   // 全部終わるまでここで待つ

    使うのは3つだけです。

    プレーンテキスト

    Add(1)   これから1つ始める、と数を増やす
    Done()   1つ終わった、と数を減らす
    Wait()   数が0になるまで待つ

    defer と組み合わせる

    Go

    go func() {
    	defer wg.Done()
    	// 何をしても、抜けるときに必ず Done が呼ばれる
    }()

    第4章でやった defer がここで効きます。処理の途中で return しても、Done の呼び忘れが起こりません。

    Done を呼び忘れると Wait が永久に終わりません。 defer で書くのは、そのための保険です。

    Add はゴルーチンの外で

    Go

    for _, item := range items {
    	wg.Add(1)      // 外。正しい
    	go func() {
    		// wg.Add(1) をここに書くと間違い
    		defer wg.Done()
    	}()
    }
    wg.Wait()

    中に書くと、Add が実行される前に Wait に到達することがあります。数が0のままなので、待たずに素通りします。

    始まる前に数える。これが Add を外に置く理由です。

    結果をどう受け取るか

    WaitGroup は完了を待つだけで、値は運びません。結果が要るなら、別に用意します。

    Go

    results := make([]int, len(items))
    for i, item := range items {
    	wg.Add(1)
    	go func(idx int, it Item) {
    		defer wg.Done()
    		results[idx] = process(it)   // 添字が違うので衝突しない
    	}(i, item)
    }
    wg.Wait()

    スライスの別々の場所に書くので、同時に書いても問題ありません。同じ変数に足し込むと壊れます。それが次のレッスンの話です。

    引数で渡す理由

    Go

    go func(idx int, it Item) { ... }(i, item)

    ループの変数をそのまま使わず、引数で渡しています。第4章の defer で「引数はその場で確定する」と書いたのと同じ理由です。

    Go 1.21 までは、ゴルーチンが動く頃にはループが先に進んで変数が変わっている、という有名な落とし穴がありました。Go 1.22 でループ変数は反復ごとに新しく作られるようになり、この問題は起きなくなっています。

    それでも引数で渡す書き方を勧めるのは、何をゴルーチンに渡したのかが読んで分かるからです。外側の変数を暗黙に掴むより、渡すものを明示するほうが後から追えます。

    要件

    1. 各要素の計算をゴルーチンで走らせる
    2. sync.WaitGroup で全部の完了を待つ
    3. Add はゴルーチンの外で呼ぶ
    4. Done は defer で呼ぶ
    5. 結果を元の順番のままカンマ区切りで返す

    ヒント

    初期コードはゴルーチンを使わず素直に計算しています。`wg.Add(1)` と `go func(...)` の形に書き換えてください

    `go func(idx int, v int) { defer wg.Done(); results[idx] = v * v }(i, n)` の形です。引数で渡すのを忘れないでください

    `wg.Wait()` をループの後に置きます。これが無いと結果が揃う前に文字列を組み立ててしまいます

    生田 陸人
    監修生田 陸人
    ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
    編集 ゆめさく編集部·公開 2026/08/10

    関連レッスン

    • 並行の落とし穴

      同じ変数を複数のゴルーチンが触ると壊れることを知り、Mutexで守れるようになります。

    • つくる: 並行集計

      第7章の知識でカテゴリ別の集計を並行に実行し、結果を安全にまとめられるようになります。

    • 第7章クイズ

      ゴルーチン、チャネル、WaitGroup、データ競合についての理解を確認します。

    • サーバーを立てる

      net/httpでHTTPサーバーを立て、リクエストに応答を返せるようになります。

    このレッスンに出てくる用語

    意味があいまいなまま進んだ語は、ここから読み直せます。

    • 処理計算や代入を表す長方形
    • スライス範囲指定で部分列を取り出す記法
    • 変数データに名前をつけて参照する仕組み
    • 引数位置引数=順番で渡す。
    • ループ繰り返し処理。矢印で戻すか専用記号で示す
    • 反復色やフォントを繰り返して秩序を生む
    main.go
    エディタを読み込んでいます

    メモ

    待ち合わせ

    ⌘S で保存