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

我对 golang 编程很陌生,我有以下程序产生deadlock,我不明白为什么?


另一件事是如果我在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()

}

输出是:


Got from ch1  0

Got from ch1  1

Got from ch1  2

Got from ch1  3

Got from ch1  4

Got from ch1  5

Got from ch1  6

Got from ch1  7

Got from ch1  8

Got from ch1  9

Got from ch2  0

Got from ch2  1

Got from ch2  2

Got from ch2  3

Got from ch2  4

Got from ch2  5

Got from ch2  6

Got from ch2  7

Got from ch2  8

Got from ch2  9

Got from ch3  0

Got from ch3  1

Got from ch3  2

Got from ch3  3

Got from ch3  4

Got from ch3  5

Got from ch3  6

Got from ch3  7

Got from ch3  8

Got from ch3  9

CLOSED

fatal error: all goroutines are asleep - deadlock!


goroutine 1 [select]:

main.main()

        c:/PraveenData/demo/go-work/main.go:29 +0x915

exit status 2



动漫人物
浏览 182回答 2
2回答

喵喔喔

你遇到死锁的原因是break你select唯一的内部打破了select,让for循环自由地重新进入选择,没有一个通道准备好从中读取。您可以通过执行以下操作来挽救它:done := falsefor !done {&nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;...&nbsp; &nbsp; &nbsp; &nbsp; case <-chClose:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; done = true&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("CLOSED")&nbsp; &nbsp; &nbsp; &nbsp; }}这很for容易让循环终止。另一种是使用标签:OuterLoop:&nbsp; &nbsp; &nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case <-chClose:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("CLOSED")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break OuterLoop&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }在这种情况下,我个人对第一个版本有一点偏好,但这只是个人喜好问题。

呼如林

你break在你的程序结束时只打破select(并再次进入循环,因此陷入僵局):用return工作正常替换它:https&nbsp;:&nbsp;//play.golang.org/p/j5bDaj3z7y事实上,从规格:“break”语句会终止同一个函数中最里面的“for”、“switch”或“select”语句的执行。您可以通过return(如我所做的)、goto 或其他一些架构重构来解决这个问题。至于无限循环,也是同样的问题,而不是封闭通道总是返回,所以当break退出 时select,你进入循环,并nil永远从封闭通道接收s
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go