Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

goroutine

goroutineはGoが提供する軽量スレッドです。『go』キーワードを関数呼び出しの前に付けるだけで、その関数を別の実行フローで並行実行できます。

構文
// 関数をgoroutineとして起動します。
go 関数名(引数)

// 無名関数をgoroutineとして起動します。
go func() {
    // 並行して実行される処理
}()

// goroutineは非常に軽量で、同時に数千〜数百万個起動できます。
// ただし main() が終了するとすべてのgoroutineも終了します。
goroutine の特徴
特徴概要
軽量OSスレッドより大幅に軽量で、初期スタックサイズは数KB程度です。必要に応じて動的に拡張されます。
Goランタイム管理GoのランタイムがgoroutineをOSスレッドにマッピングします。M個のOSスレッドにN個のgoroutineを効率よくスケジュールします(M:Nモデル)。
非同期実行『go』で起動した関数はすぐに制御を返します。呼び出し元はgoroutineの完了を待ちません。
完了待ちgoroutineの完了を待つには、channelまたは『sync.WaitGroup』を使います。
パニックの伝播goroutine内のpanicは呼び出し元には伝播しません。各goroutineで個別にrecover()する必要があります。
サンプルコード
package main

import (
    "fmt"
    "sync"
    "time"
)

// 処理を行う関数です。
func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done() // 処理終了時にWaitGroupに通知します。
    fmt.Printf("Worker %d: 開始\n", id)
    time.Sleep(time.Millisecond * 100) // 重い処理のシミュレーションです。
    fmt.Printf("Worker %d: 完了\n", id)
}

func main() {
    // 単純なgoroutineの起動です。
    go fmt.Println("別のgoroutineから出力します") // 非同期で実行されます。

    // WaitGroupでgoroutineの完了を待ちます。
    var wg sync.WaitGroup

    // 5つのgoroutineを起動します。
    for i := 1; i <= 5; i++ {
        wg.Add(1)       // goroutine起動前にカウントを増やします。
        go worker(i, &wg)
    }

    wg.Wait() // すべてのgoroutineが完了するまで待ちます。
    fmt.Println("すべてのworkerが完了しました")

    // 無名関数をgoroutineとして起動します。
    // ループ変数を引数で渡すことで値をキャプチャします。
    var wg2 sync.WaitGroup
    results := make([]int, 5)
    for i := 0; i < 5; i++ {
        wg2.Add(1)
        go func(idx int) {
            defer wg2.Done()
            results[idx] = idx * idx // 各goroutineが独立したインデックスを処理します。
        }(i) // ループ変数 i を引数として渡します。
    }
    wg2.Wait()
    fmt.Println("二乗の結果:", results) // 『[0 1 4 9 16]』と出力されます。
}
概要

goroutineはGoの並行処理の根幹です。OSスレッドと異なり非常に軽量なため、数千〜数百万のgoroutineを同時に実行できます。ただしgoroutine間でデータを共有する場合は同期処理が必要です。

ループ内でgoroutineを起動する場合、ループ変数を直接クロージャでキャプチャすると、すべてのgoroutineが同じ最終値を参照するバグが発生します。必ず引数として渡してください。

goroutineの完了を待つ方法として、『sync.WaitGroup』と『channel』があります。共有データへの安全なアクセスには『sync.Mutex』を使用してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。