例による Go: チャンネルのクローズ

クローズとは、チャンネルにこれ以上値が送信されないことを示します。これは、完了をチャネルの受信者に伝えるために便利です。

package main
import "fmt"

この例では、jobs チャネルを使用して、main() ゴルーチンからワーカーゴルーチンに実行する作業を伝えます。ワーカーのジョブがなくなると、jobs チャネルをクローズします。

func main() {
    jobs := make(chan int, 5)
    done := make(chan bool)

ワーカーゴルーチンを以下に示します。これは、j, more := <-jobs を何度も使用して jobs から受信します。この特別な 2 つの値の形式の受信では、jobsクローズされ、チャンネル内のすべての値が既に受信されている場合、more の値は false になります。これを使用して、すべてのジョブを処理するときに done を通知します。

    go func() {
        for {
            j, more := <-jobs
            if more {
                fmt.Println("received job", j)
            } else {
                fmt.Println("received all jobs")
                done <- true
                return
            }
        }
    }()

jobs チャネルを介してワーカーに 3 つのジョブを送信し、その後ジョブをクローズします。

    for j := 1; j <= 3; j++ {
        jobs <- j
        fmt.Println("sent job", j)
    }
    close(jobs)
    fmt.Println("sent all jobs")

以前見た同期アプローチを使用してワーカーを待機します。

    <-done

クローズされたチャンネルからの読み込みはすぐに成功し、基になる型のゼロ値を返します。オプションの 2 番目の戻り値は、受信した値がチャンネルへの正常な送信操作によって配信された場合は true、チャンネルがクローズされて空であるため生成されたゼロ値の場合は false です。

    _, ok := <-jobs
    fmt.Println("received more jobs:", ok)
}
$ go run closing-channels.go 
sent job 1
received job 1
sent job 2
received job 2
sent job 3
received job 3
sent all jobs
received all jobs
received more jobs: false

クローズされたチャンネルというアイデアは、次の例、チャンネルの range 処理に自然につながります。

次の例: チャンネルの範囲処理