我一直在尝试解决我在Golang并发中遇到的这个简单问题。我一直在搜索所有可能的解决方案,但没有发现与我的问题有关的特定信息(否则我可能会被遗漏)。这是我的代码:
package main import ( "fmt" "time" ) func producer(ch chan int, d time.Duration, num int) { for i:=0; i<num; i++ { ch <- i time.Sleep(d) } } func main() { ch := make(chan int) go producer(ch, 100*time.Millisecond, 2) go producer(ch, 200*time.Millisecond, 5) for { fmt.Println(<-ch) } close(ch) }
它显示错误:
致命错误:所有goroutine都在睡觉-死锁! goroutine 1 [chan接收]:main.main()D:/Code/go/src/testconcurrency/main.go:23 + 0xca退出状态2
致命错误:所有goroutine都在睡觉-死锁!
goroutine 1 [chan接收]:main.main()D:/Code/go/src/testconcurrency/main.go:23 + 0xca退出状态2
避免此错误的有效方法是什么?,谢谢。
您需要在goroutine中同步所有异步过程。您的主线程和goroutine线程不是同步进程。您的主线程永远不会知道何时停止从goroutines调用通道。因为您的主线程在通道上循环,所以它总是从通道中调用值,并且当goroutine完成并且通道停止发送值时,您的主线程无法再从通道中获取值,因此条件变为死锁。为了避免这种使用sync.WaitGroup来同步异步过程。
sync.WaitGroup
这是代码:
package main import ( "fmt" "time" "sync" ) func producer(ch chan int, d time.Duration, num int, wg *sync.WaitGroup) { for i:=0; i<num; i++ { ch <- i; time.Sleep(d); } defer wg.Done(); } func main() { wg := &sync.WaitGroup{} ch := make(chan int); wg.Add(2); go producer(ch, 100*time.Millisecond, 2, wg); go producer(ch, 200*time.Millisecond, 5, wg); go func() { wg.Wait() close(ch) }() // print the outputs for i:= range ch { fmt.Println(i); } }
https://play.golang.org/p/euMTGTIs83g
希望能帮助到你。
由于我的解决方案看起来与已回答的问题有点相似,因此我将其更改为我的原始回答,然后进行修改以适应OP问题。
package main import ( "fmt" "time" "sync" ) // producer produce values tobe sent to consumer func producer(ch chan int, d time.Duration, num int, wg *sync.WaitGroup) { defer wg.Done(); for i:=0; i<num; i++ { ch <- i; time.Sleep(d); } } // consumer consume all values from producers func consumer(ch chan int, out chan int, wg *sync.WaitGroup) { defer wg.Done(); for i:= range ch { out <- i } } // synchronizer synchronize all goroutines to avoid deadlocks func synchronizer(ch chan int, out chan int, wgp *sync.WaitGroup, wgc *sync.WaitGroup) { wgp.Wait() close(ch) wgc.Wait() close(out) } func main() { wgp := &sync.WaitGroup{} wgc := &sync.WaitGroup{} ch := make(chan int); out := make(chan int); wgp.Add(2); go producer(ch, 100*time.Millisecond, 2, wgp); go producer(ch, 200*time.Millisecond, 5, wgp); wgc.Add(1); go consumer(ch, out, wgc) go synchronizer(ch, out, wgp, wgc) // print the outputs for i:= range out { fmt.Println(i); } }
将consumergoroutine用于fan-in来自多个goroutine的所有输入,并从goroutine读取所有值consumer。
consumer
fan-in