0Pricing
Go Academy · レッスン

ゴルーチンの起動

goキーワード、ゴルーチンのライフサイクル、WaitGroup

「ゴルーチンの起動」はCoddyKit上の無料Go Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはGo Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Go Academyコースには全4レッスンが含まれています。

ゴルーチンとは

ゴルーチンは、Goランタイムによって管理される軽量な並行実行関数です。ゴルーチンはOSスレッドよりもはるかに低コストなので、数千個を実行できます:

  • goキーワードで開始します
  • 初期スタックは約2KBです(動的に拡張されます)
  • OSではなくGoランタイムによってスケジュールされます
  • 共有メモリではなく、チャネルを介して通信します

goキーワード

関数呼び出しの前に goを付けると、ゴルーチンとして起動できます:

package main
import ("fmt"; "time")

func greet(name string) {
    fmt.Printf("Hello, %s!\n", name)
}

func main() {
    go greet("Alice")   // runs concurrently
    go greet("Bob")     // runs concurrently
    time.Sleep(100 * time.Millisecond) // wait for goroutines
    fmt.Println("done")
}

ゴルーチンのライフサイクル

ゴルーチンは goステートメントが実行されたときに開始し、その関数が戻ると終了します。mainが戻ると、すべてのゴルーチンが終了します:

package main
import ("fmt"; "time")

func worker(id int) {
    fmt.Printf("Worker %d starting\n", id)
    time.Sleep(time.Duration(id) * 50 * time.Millisecond)
    fmt.Printf("Worker %d done\n", id)
}

func main() {
    for i := 1; i <= 3; i++ {
        go worker(i)
    }
    time.Sleep(300 * time.Millisecond) // naive wait
}

同期に使うsync.WaitGroup

ゴルーチンの完了を待つには、スリープではなく sync.WaitGroupを使用します:

package main
import ("fmt"; "sync")

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()  // signal completion
    fmt.Printf("Worker %d working\n", id)
}

func main() {
    var wg sync.WaitGroup
    for i := 1; i <= 5; i++ {
        wg.Add(1)           // register one goroutine
        go worker(i, &wg)
    }
    wg.Wait()               // block until all Done()
    fmt.Println("all workers finished")
}

匿名ゴルーチン

匿名関数をゴルーチンとして直接起動します。インラインの並行タスクに便利です:

package main
import ("fmt"; "sync")

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
        i := i  // capture loop variable
        wg.Add(1)
        go func() {
            defer wg.Done()
            fmt.Printf("goroutine %d\n", i)
        }()
    }
    wg.Wait()
}

ループ変数のキャプチャに関する注意点

ループ変数をキャプチャしないと、すべてのゴルーチンが同じ(最後の)値を参照する可能性があります。これはGoでよくある並行処理のバグです:

package main
import ("fmt"; "sync")

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go func(n int) {  // pass i as argument — safe
            defer wg.Done()
            fmt.Println(n)  // prints 0, 1, 2 in some order
        }(i)
    }
    wg.Wait()
}

ゴルーチンとスレッドの比較

OSスレッドよりもゴルーチンが推奨される理由:

  • 初期スタックは2KBで、OSスレッドの約1MBより小さい
  • 作成にかかる時間はミリ秒ではなくマイクロ秒です
  • Goランタイムは、GOMAXPROCS個のOSスレッド上でゴルーチンを多重化します
  • ゴルーチンの切り替えは協調的に行われ、カーネルは関与しません
  • スケジューリングはGoが処理するため、ロジックに集中できます

GOMAXPROCS

runtime.GOMAXPROCSは、ゴルーチンを並列に実行するOSスレッドの数を制御します(デフォルトはCPU数です):

package main
import ("fmt"; "runtime")

func main() {
    // Default: number of available CPU cores
    fmt.Println("CPUs:", runtime.NumCPU())
    fmt.Println("GOMAXPROCS:", runtime.GOMAXPROCS(0)) // 0 = query without changing

    // Set to 1 for debugging race conditions:
    // runtime.GOMAXPROCS(1)

    fmt.Println("Goroutines:", runtime.NumGoroutine())
}

ゴルーチンリーク

ゴルーチンリークは、ゴルーチンが起動されたものの、決して終了しない場合に発生します。よくある原因は、チャネルの受信待ち、ミューテックスのロック待ち、キャンセル処理がないことです:

package main
import ("fmt"; "time"; "runtime")

func leaky() {
    ch := make(chan int)  // nobody sends to ch
    go func() {
        v := <-ch  // blocks forever — goroutine leaked!
        fmt.Println(v)
    }()
}

func main() {
    leaky()
    time.Sleep(10 * time.Millisecond)
    fmt.Println("goroutines:", runtime.NumGoroutine()) // > 1
}

ゴルーチンのベストプラクティス

ゴルーチンに関するガイドライン:

  • ゴルーチンがどのように終了するかを必ず把握します
  • 同期にはスリープではなく、WaitGroupまたはチャネルを使用します
  • ループ変数はクロージャ経由ではなく、関数の引数として渡します
  • コンテキストでゴルーチンをキャンセルし、実行したまま放置しないようにします
  • 競合検出器を使用します: go run -race main.go

確認問題

ゴルーチンでループ変数のキャプチャバグを回避する正しい方法は何ですか?

復習: ゴルーチンの起動

まとめ:

  • go fn()で起動します — 軽量で低コストです
  • 待機には sync.WaitGroupを使用します: Add(1)、defer Done()、Wait()
  • ループ変数は引数または再宣言によってキャプチャします
  • 各ゴルーチンがどのように終了するかを必ず把握し、リークを防ぎます
  • データ競合の検出には -raceフラグを使用します

よくある質問

「ゴルーチンの起動」レッスンは無料ですか?

はい。「ゴルーチンの起動」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Go Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Go Academyコースには全4レッスンが含まれています。

「ゴルーチンの起動」で何を学びますか?

goキーワード、ゴルーチンのライフサイクル、WaitGroup ブラウザで直接実行するハンズオンコードでGo Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Go Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのGo Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「ゴルーチンの起動」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このGo Academyレッスンでコードを書いて実行できますか?

はい。すべてのGo Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. ゴルーチンの起動
  2. バッファなしチャネル
  3. バッファ付きチャネル
  4. チャネルの方向とパイプラインパターン
← Go Academyに戻る