技術向上

プログラミングの学び、気になるテクノロジーやビジネストレンドを発信

rangeの無限ループとgoroutine【Go】

for rangeの対象が、無限ループによって生成(更新)される場合、
for rangeの処理も終わらないため、下に記述された処理が行われません。

c := make(chan int)

go func() {
    defer close(c)
    var i int
    for {    // 無限ループ
        c <- i
        time.Sleep(1 * time.Second)
        i++
    }
}()

for v := range c {    // 上記goroutineのforループが無限処理のため、このfor range以降の処理がブロックされてしまう
    fmt.Println(v)
}

fmt.Println("blablabla")    // 処理されない


for rangeを囲む新たなgoroutineを作成し、並行処理の対象にします。
これにより、そのgoroutineの処理の終了を待たずに、下に続く処理が開始されます。

c := make(chan int)
var wg sync.WaitGroup

go func() {
    var i int
    for {   // 無限ループ
        wg.Add(1)
        c <- i
        time.Sleep(1 * time.Second)
        i++
    }
}()

go func() {    // 新たなgoroutineを作り、並行処理の対象とする
    for v := range c {
        defer wg.Done()
        fmt.Println(v)
    }
}()

fmt.Println("blablabla")    // 上記処理がgoroutine化されたため、ブロックされなくなり処理される
wg.Wait()    // Addした分、Doneされたらmain関数を終了(producerが無限ループのため、終了しない)


起き得るケースとして、for rangeを含むメソッドや関数などを呼び出した後に
処理を追加したものの、処理が実行されない、ということがあるかと思います。
そのような際は事実を確認の上、応急処置として、for rangeのgoroutine化を試してみると良いでしょう。