Example below works fine (not sure if it is the best practise though) with/without explicitly closing channels. However, what I want to know is, is there any value/benefit of explicitly closing channels or leaving it to memory manager to handle/close them?
Some resources confusing and make similar remarks such as:
Close what you opened after finishing with them.
Don’t worry too much about closing channels because Go is good at handling things like that.
I have a strong feeling that, it is better to close them because a book I read reads: “Channels carry overhead and have performance impact… Channnels are single biggest source of memory management issues in Go programs.”
Note: I know I could use “timeout” to exit the loop but using done channel on purpose.
package main
import (
"fmt"
)
func main() {
fmt.Println("main: begin")
names := []string{"John", "Robert", "Al", "Rick"}
msg := make(chan string)
done := make(chan bool)
go greet(msg, done, names)
Loop:
for {
select {
case m := <-msg:
fmt.Println(m)
case <-done:
fmt.Println("main: done")
//close(done)
break Loop
}
}
fmt.Println("main: end")
}
func greet(msg chan<- string, done chan<- bool, name []string) {
for _, name := range name {
msg <- fmt.Sprintf("Hi %s!", name)
}
//close(msg)
done <- true
}
main: begin
Hi John!
Hi Robert!
Hi Al!
Hi Rick!
main: done
main: end
Note that in your example a single channel msg would be enough. As soon as greet calls close(msg), a for loop readig values m := <-msg would end. The second chanel done and the select are not necessary.
But I guess this is not what you question is about
@GreyShatter I read it before and I think too much going on there. I lost my bearings.
@lutzhorn Do you mind showing me how exactly I should refactor it because when I do what you suggest, it either prints once and exit or don’t exit at all. I bet am missing something.
Excellent. Thanks. I remember seeing range bit before but completely forgot about it. Now it is time for me to wait for comments on “to close or not to close channels” question.
package main
import (
"fmt"
)
func main() {
fmt.Println("main: begin")
names := []string{"John", "Robert", "Al", "Rick"}
msg := make(chan string)
go greet(msg, names)
// A: Using range on the channel will loop until the channel is closed.
for m := range msg {
fmt.Println(m)
}
fmt.Println("main: end")
}
func greet(msg chan<- string, name []string) {
for _, name := range name {
msg <- fmt.Sprintf("Hi %s!", name)
}
// Closing msg here will terminate the loop at A.
close(msg)
}