For the below code:
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)
}
Below is the output:
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
Why sender go-routine does not close the channel?
Your main
goroutine ends without coordinating with the emit goroutine to know that it's finished. When the end of main
is reached, the program - and all its goroutines - ends regardless of whether any go routines may still be processing, unless you explicitly wait for them.
Closing the channel can help communicate the emit
goroutine's completion to main
. In this case, and using the two-value response from the channel read as in
word, ok = <-wordChannel
does expose the state of the channel (open or closed) to main
, but you never use it to control the flow of main. Further, you have an exact the number of reads hard coded into main. So, even if you were controlling flow with a channel close , you would never attempt a final read to see the closed channel.
Luckily, the solution with go can be quite simple. range
ing over a go channel will read values until the channel is closed. So you can simplify your code, remove the explicit number of channel receives, and use the channel close to signify emit
's completion, all with this more concise version:
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)
}
}
When I run this, I get what I perceive to be your desired output:
$ 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
This "range
over a channel
" syntax is conceptually equivalent to something like this, just a little more elegant looking:
func main() {
wordChannel := make(chan string)
go emit(wordChannel)
for {
if word, ok := <-wordChannel; ok {
fmt.Printf("receive %s \n", word)
} else {
break
}
}
}