请看下面的代码片段。
package main
import (
"errors"
"fmt"
"math/rand"
"runtime"
"sync"
"time"
)
func random(min, max int) int {
rand.Seed(time.Now().Unix())
return rand.Intn(max-min) + min
}
func err1(rand int, chErr chan error, wg *sync.WaitGroup) {
if rand == 1 {
chErr <- errors.New("Error 1")
}
wg.Done()
}
func err2(rand int, chErr chan error, wg *sync.WaitGroup) {
if rand == 2 {
chErr <- errors.New("Error 2")
}
wg.Done()
}
func err3(rand int, chErr chan error, wg *sync.WaitGroup) {
if rand == 3 {
chErr <- errors.New("Error 3")
}
wg.Done()
}
func err4(rand int, chErr chan error, wg *sync.WaitGroup) {
if rand == 3 {
chErr <- errors.New("Error 4")
}
wg.Done()
}
func err5(rand int, chErr chan error, wg *sync.WaitGroup) {
if rand == 4 {
chErr <- errors.New("Error 5")
}
wg.Done()
}
func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
chErr := make(chan error, 1)
wg := new(sync.WaitGroup)
//n := random(1, 8)
n := 3
fmt.Println(n)
wg.Add(5)
go err1(n, chErr, wg)
go err2(n, chErr, wg)
go err3(n, chErr, wg)
go err4(n, chErr, wg)
go err5(n, chErr, wg)
fmt.Println("Wait")
wg.Wait()
select {
case err := <-chErr:
fmt.Println(err)
close(chErr)
default:
fmt.Println("NO error, job done")
}
}
如何避免这里出现死锁?我可以分配缓冲区长度 2,但也许它有更优雅的方法来解决问题。
我有意识地对函数 err3 和 err4 执行了 rand == 3。
最佳答案
您的程序已死锁,因为您的 channel 已满。
您的 channel 大小为 1。然后调用 wg.Wait()
.. 等待调用 5 个函数。现在,一旦您到达 err3
.. rand == 3
,因此在您的 channel 上传递了一个错误。
此时,您的 channel 已满,您只勾选了 3 个 WaitGroup 项目。
err4
以值 3 .. 调用,它也想在您的 channel 上放一个错误。此时,它会阻塞 - 因为您的 channel 已满并且没有任何内容从中弹出。
所以你的主 goroutine 会阻塞,因为你的 WaitGroup 永远不会完成。
修复确实是让您的 channel 缓冲区更大。这样,当错误试图放置在 channel 上时 - 它不会阻塞,并且您的 WaitGroup 有机会勾选其所有项目。
关于go - 我怎样才能避免死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28063465/