// 下面是 Worker goroutine。它以 j, more := <-jobs 的形式重复接收来自作业的信息 // 在这种特殊的 2 值接收形式中,如果 jobs 已关闭,且通道中的所有值都已接收完毕,则 more 值将为 false // 当我们完成所有工作时,我们会用它来通知 done gofunc() { for { j, more := <-jobs if more { fmt.Println("received job", j) } else { fmt.Println("received all jobs") done <- true return } } }()
// 这会通过 jobs 通道向 Worker 发送 3 个job,然后关闭它 for j := 1; j <= 3; j++ { jobs <- j fmt.Println("sent job", j) } close(jobs) fmt.Println("sent all jobs")
// 我们使用之前看到的同步方法来等待 Worker <-done
// 从关闭的通道读取数据会立即成功,并返回底层类型的零值 // 如果接收到的值是通过成功发送操作传送到通道的,则第二个可选返回值为 true // 如果接收到的值是因通道关闭且为空而生成的零值,则第二个可选返回值为 false _, ok := <-jobs fmt.Println("received more jobs:", ok) }
log
1 2 3 4 5 6 7 8 9 10
$ 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 over Channels
在前面的示例中,我们看到了 for 和 range 如何提供对基本数据结构的迭代。我们也可以使用这种语法迭代从通道接收到的值。