Reputation: 73
I'm new to Go and I am also kinda having a hard time reading the documentation. Can anyone help explain what is wrong with the code below
package main
import (
"fmt"
)
func main() {
c := make(chan int)
for i := 0; i < 10; i++ {
go func() {
add(c)
}()
}
close(c)
for v := range c {
fmt.Println(v)
}
}
func add(c chan<- int) {
c<-123
}
Upvotes: 6
Views: 2803
Reputation: 434
Your first loop tries to send a value to an unbuffered channel, which means every go routine in the loop will be blocked until the sent value is received.
After the first loop, the main go routine closes the channel, so we never know how many of 10 go routines will actually be spun up. This is the first wrong point.
for - range
loop receives values from the channel until it's closed, but because you already closed the channel before the second loop, the second loop won't iterate though the channel at all. This is the second wrong point.
Below code works though, because the sender goroutine closes the channel after sending all the values. This ensures that the main goroutine can receive all the values sequentially without causing a deadlock.
package main
import "fmt"
func main() {
c := make(chan int)
go func() {
for i := 0; i < 10; i++ {
add(c)
}
close(c)
}()
for v := range c {
fmt.Println(v)
}
}
func add(c chan<- int) {
c <- 123
}
Upvotes: 1
Reputation: 1
Your loop is generating 10 goroutines.
Closing a channel should only be done by a go-routine that is adding to a channel but because you have so many is hard to decide which go-routine is going to close it.
Adding the close(chan) outside the for loop causes some of the 10 goroutines to push to a closed channel which leads to a panic.
Your options are limited in this case to either use waitgroups as suggested above or given you know how many routines you are generating you can loop 10 times to read the messages instead of ranging on the channel like so:
package main
import (
"fmt"
)
func main() {
c := make(chan int)
for i := 0; i < 10; i++ {
go func() {
add(c)
}()
}
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
}
func add(c chan<- int) {
c <- 123
}
Upvotes: 0
Reputation: 751
Based on the suggestion from icza :
package main
import (
"fmt"
"sync"
)
func main() {
c := make(chan int)
var wgConsumer sync.WaitGroup
wgConsumer.Add(1)
go func() {
defer wgConsumer.Done()
for v := range c {
fmt.Println(v)
}
}()
var wg sync.WaitGroup
wg.Add(10)
for i := 0; i < 10; i++ {
go func() {
add(c)
defer wg.Done()
}()
}
wg.Wait()
close(c)
wgConsumer.Wait()
}
func add(c chan<- int) {
c <- 123
}
Output:
123
123
123
123
123
123
123
123
123
123
Upvotes: 2