Go 为什么我的围棋程序出现死锁?

Go 为什么我的围棋程序出现死锁?,go,Go,我对golang编程非常陌生,我有以下产生死锁的程序,我不明白为什么 另一件事是,如果我在doAdd方法中关闭通道,那么我将进入一个无限循环,这对我来说也有点奇怪 这是节目单 var wg sync.WaitGroup func main() { ch1 := make(chan string) ch2 := make(chan string) ch3 := make(chan string) chClose := make(chan bool) wg

我对golang编程非常陌生,我有以下产生死锁的程序,我不明白为什么

另一件事是,如果我在
doAdd
方法中关闭通道,那么我将进入一个无限循环,这对我来说也有点奇怪

这是节目单

var wg sync.WaitGroup

func 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()
}

程序末尾的
中断
只会中断
选择
(并再次进入循环,因此出现死锁):将其替换为
返回
效果良好:

事实上,从以下方面:

“break”语句终止同一函数中最内层的“for”、“switch”或“select”语句的执行

您可以通过
返回
(就像我做的那样)、goto或其他一些架构重构来解决这个问题


至于无限循环,这是同样的问题,相反,封闭通道总是返回,因此当
中断
退出
选择
时,您返回循环,并从封闭通道接收
s,直到永久

您的
中断
在程序结束时仅中断
选择
(并再次进入循环,因此出现死锁):将其替换为
return
可以正常工作:

事实上,从以下方面:

“break”语句终止同一函数中最内层的“for”、“switch”或“select”语句的执行

您可以通过
返回
(就像我做的那样)、goto或其他一些架构重构来解决这个问题


至于无限循环,这是同样的问题,相反,封闭通道总是返回,因此当
中断
退出
选择
时,您返回循环,并从封闭通道永远接收
死锁的原因是
中断
选择
中y从
select
中断,让
for
循环自由地重新进入select,此时没有任何通道准备好读取

您可以通过执行以下操作来拯救此问题:

done := false

for !done {
        select {
               ...
        case <-chClose:
                done = true
                fmt.Println("CLOSED")
        }
}

一、 就个人而言,在这种情况下,对第一个版本有一点偏好,但这只是口味的问题。

出现死锁的原因是
select
中的
break
只会从
select
中中断,让
for
循环自由地重新进入select,其中没有任何频道我们已经准备好阅读

您可以通过执行以下操作来拯救此问题:

done := false

for !done {
        select {
               ...
        case <-chClose:
                done = true
                fmt.Println("CLOSED")
        }
}

一、 就个人而言,在这种情况下,对第一个版本有一点偏好,但这仅仅是口味的问题。

也有标签的break也有标签的break
OuterLoop:
        for {
                select {
                ...
                case <-chClose:
                        fmt.Println("CLOSED")
                        break OuterLoop
                }
        }