对于下面的代码。
package main
import "fmt"
func emit(c chan string) {
words := []string{"The", "quick", "brown", "fox", "ran", "away"}
for _, word := range words {
fmt.Printf("send %s\n", word)
c <- word
}
fmt.Printf("Close the channel\n")
close(c)
}
func main() {
wordChannel := make(chan string)
go emit(wordChannel)
word := <-wordChannel
fmt.Printf("receive %s \n", word)
word = <-wordChannel
fmt.Printf("receive %s \n", word)
word = <-wordChannel
fmt.Printf("receive %s \n", word)
word, ok := <-wordChannel
fmt.Printf("receive %s %t\n", word, ok)
word, ok = <-wordChannel
fmt.Printf("receive %s %t\n", word, ok)
word, ok = <-wordChannel
fmt.Printf("receive %s %t\n", word, ok)
}
下面是输出。
send The
send quick
receive The
receive quick
send brown
send fox
receive brown
receive fox true
send ran
send away
receive ran true
receive away true
为什么sender go-routine没有关闭通道?
您的"..."。main
goroutine结束时,不需要与emit goroutine协调就可以知道它已经结束了。 当 main
的时候,程序和它的所有goroutines都会结束,不管是否有任何go例程还在处理,除非你明确地等待它们。
关闭通道 可以 有助于传达 emit
戈鲁丁的完成情况 main
. 在这种情况下,并使用从通道读取的两个值响应,如在
word, ok = <-wordChannel
是否 将通道的状态(打开或关闭)暴露给 main
但你从来没有用它来控制main的流量。 此外,你有一个 确切 读数 暗码 入主。 所以,即使你 是 用通道关闭来控制流量,你永远不会尝试最终读取来查看关闭的通道。
幸运的是,go的解决方案非常简单。 range
在一个go通道上进行读取,直到通道关闭。 因此,你可以简化你的代码,去掉显式的通道接收数,用通道关闭来表示。emit
的完成,都用这个更简洁的版本。
package main
import "fmt"
func emit(c chan string) {
words := []string{"The", "quick", "brown", "fox", "ran", "away"}
for _, word := range words {
fmt.Printf("send %s\n", word)
c <- word
}
fmt.Printf("Close the channel\n")
close(c)
}
func main() {
wordChannel := make(chan string)
go emit(wordChannel)
for word := range wordChannel {
fmt.Printf("receive %s \n", word)
}
}
当我运行这个时,我得到了我认为是你想要的输出。
$ go run t.go
send The
send quick
receive The
receive quick
send brown
send fox
receive brown
receive fox
send ran
send away
receive ran
receive away
Close the channel
这个"range
在一个 channel
"语法在概念上相当于这样的东西,只是看起来更优雅一些。
func main() {
wordChannel := make(chan string)
go emit(wordChannel)
for {
if word, ok := <-wordChannel; ok {
fmt.Printf("receive %s \n", word)
} else {
break
}
}
}