I am getting "fatal error: all goroutines are asleep - deadlock! " for some reason in the below code. I am using buffered channel which should be non-blocking. Not sure what I am doing wrong
package main
import (
"fmt"
"sync"
)
func main() {
c := make(chan int, 2)
var wg sync.WaitGroup
wg.Add(2)
go doSomething(c, wg)
go doSomething(c, wg)
go doSomething(c, wg)
wg.Wait()
close(c)
for v := range c {
fmt.Print(v)
}
}
func doSomething(c chan<- int, wg sync.WaitGroup) {
defer wg.Done()
c <- 1
}
Playground link https://play.golang.org/p/J9meD5aKna
While your solution might work I'm not happy with it.
First, the fact that you need to change the channel size to make it work indicates that there is a potential problem / bug. Now each time you want to launch another doSomething
you have to remember to change channel's length.
Second, you wait until all the goroutines are finished before reading from the channel. This is kind of "waste" as one of the main points of range loop over an channel is that you don't have to wait until all the items are generated (written into channel), you can start processing the items as soon as some of them are ready.
So I would write your code as something like
func main() {
c := make(chan int)
var wg sync.WaitGroup
wg.Add(3)
go func() {
doSomething(c)
defer wg.Done()
}()
go func() {
doSomething(c)
defer wg.Done()
}()
go func() {
doSomething(c)
defer wg.Done()
}()
go func() {
wg.Wait()
defer close(c)
}()
for v := range c {
fmt.Print(v)
}
}
func doSomething(c chan<- int) {
c <- 1
}
https://play.golang.org/p/T3dfiztKot
Note how the waiting and closing the channel is now in it's own goroutine - this allows to start iterating over the channel (which is now unbuffered!) right away.
I also changed the code so that the WaitGroup
never leaves the scope where it is declared (ie it isn't used as parameter), this is my personal preference. I believe it makes code easier to follow and understand.
I found the problem. Actually two problems
The size of the channel and wg should be 3
I should pass the wg as pointer
Updated code
package main
import (
"fmt"
"sync"
)
func main() {
c := make(chan int, 3)
var wg sync.WaitGroup
wg.Add(3)
go doSomething(c, &wg)
go doSomething(c, &wg)
go doSomething(c, &wg)
wg.Wait()
close(c)
for v := range c {
fmt.Print(v)
}
}
func doSomething(c chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
c <- 1
}
Yes, there is an important issues in your code.
you call go doSomething(c, wg)
just pass wg
value. you should know
Arguments in Go are always passed by value. Use a pointer when an argument may be modified.
so you should do like this go doSomething(c, &wg)
, then wg
in main
function will be modified by defer wg.Done()
in func doSomething(c chan<- int, wg sync.WaitGroup)
.
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.