为了账号安全,请及时绑定邮箱和手机立即绑定

为什么我的 go 程序会出现死锁?

为什么我的 go 程序会出现死锁?

Go
动漫人物 2022-01-10 14:58:17
我对 golang 编程很陌生,我有以下程序产生deadlock,我不明白为什么?另一件事是如果我在doAdd方法中关闭通道然后我进入一个无限循环,这对我来说也有点奇怪。这是程序。var wg sync.WaitGroupfunc main() {    ch1 := make(chan string)    ch2 := make(chan string)    ch3 := make(chan string)    chClose := make(chan bool)    wg.Add(3)    go doAdd(ch1, "ch1")    go doAdd(ch2, "ch2")    go doAdd(ch3, "ch3")    go waitForClose(chClose)    for {        select {        case x := <-ch1:            fmt.Println("Got from ch1 ", x)        case y := <-ch2:            fmt.Println("Got from ch2 ", y)        case z := <-ch3:            fmt.Println("Got from ch3 ", z)        case <-chClose:            fmt.Println("CLOSED")            break        }    }}func waitForClose(chClose chan bool) {    wg.Wait()    chClose <- true}func doAdd(ch chan string, name string) {    for i := 0; i < 10; i++ {        ch <- strconv.Itoa(i)    }    wg.Done()}输出是:Got from ch1  0Got from ch1  1Got from ch1  2Got from ch1  3Got from ch1  4Got from ch1  5Got from ch1  6Got from ch1  7Got from ch1  8Got from ch1  9Got from ch2  0Got from ch2  1Got from ch2  2Got from ch2  3Got from ch2  4Got from ch2  5Got from ch2  6Got from ch2  7Got from ch2  8Got from ch2  9Got from ch3  0Got from ch3  1Got from ch3  2Got from ch3  3Got from ch3  4Got from ch3  5Got from ch3  6Got from ch3  7Got from ch3  8Got from ch3  9CLOSEDfatal error: all goroutines are asleep - deadlock!goroutine 1 [select]:main.main()        c:/PraveenData/demo/go-work/main.go:29 +0x915exit status 2
查看完整描述

2 回答

?
喵喔喔

TA贡献1735条经验 获得超5个赞

你遇到死锁的原因是break你select唯一的内部打破了select,让for循环自由地重新进入选择,没有一个通道准备好从中读取。


您可以通过执行以下操作来挽救它:


done := false


for !done {

        select {

               ...

        case <-chClose:

                done = true

                fmt.Println("CLOSED")

        }

}

这很for容易让循环终止。


另一种是使用标签:


OuterLoop:

        for {

                select {

                ...

                case <-chClose:

                        fmt.Println("CLOSED")

                        break OuterLoop

                }

        }

在这种情况下,我个人对第一个版本有一点偏好,但这只是个人喜好问题。


查看完整回答
反对 回复 2022-01-10
?
呼如林

TA贡献1798条经验 获得超3个赞

break在你的程序结束时只打破select(并再次进入循环,因此陷入僵局):用return工作正常替换它:https : //play.golang.org/p/j5bDaj3z7y

事实上,从规格

“break”语句会终止同一个函数中最里面的“for”、“switch”或“select”语句的执行。

您可以通过return(如我所做的)、goto 或其他一些架构重构来解决这个问题。

至于无限循环,也是同样的问题,而不是封闭通道总是返回,所以当break退出 时select,你进入循环,并nil永远从封闭通道接收s


查看完整回答
反对 回复 2022-01-10
  • 2 回答
  • 0 关注
  • 181 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信