由于以下代码中的某种原因,我收到“致命错误:所有goroutine都在睡眠-死锁!”。我正在使用应该不阻塞的缓冲通道。不知道我在做什么错
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 }
游乐场链接https://play.golang.org/p/J9meD5aKna
虽然您的解决方案可能会起作用,但我对此并不满意。
首先,您需要更改通道大小以使其起作用这一事实表明存在潜在的问题/错误。现在,每次您要启动另一个时doSomething,都必须记住要更改通道的长度。
doSomething
其次,您要等到所有goroutine完成后才能从通道读取。这是一种“浪费”,因为通道范围循环的要点之一是您不必等到所有项目生成(写入通道)后,就可以立即处理这些项目。他们已经准备好了。
所以我会像这样写你的代码
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
请注意,等待和关闭通道现在是如何在其自己的goroutine中进行的-这允许立即开始在通道上进行迭代(该通道现在没有缓冲!)。
我还更改了代码,以WaitGroup使它永远不会离开声明它的范围(即,它不用作参数),这是我个人的喜好。我相信它使代码更易于遵循和理解。
WaitGroup