当向 Go 例程之外的通道发送值时,Go 例程会出现死锁

我在 Golang 教程中学习 Go select 语句时尝试对代码进行一些更改: https: //tour.golang.org/concurrency/5。但是,我遇到了问题:


fatal error: all goroutines are asleep - deadlock!


goroutine 1 [chan send]:

main.main()

        concurrency.go:26 +0xa3


goroutine 33 [chan receive]:

main.main.func1(0xc000088000)

        concurrency.go:24 +0x42

created by main.main

        concurrency.go:23 +0x89

exit status 2

这是我尝试并遇到问题的代码


func fibonacci(c, quit chan int) {

    x, y := 0, 1

    for {

        select {

            case c <- x:  //sending value x into channel c

                x, y = y, x+y

            case <-quit:    //receive value from quit

                fmt.Println("quit")

        return

        }

    }

}


func main() {

    //create two channels

    c := make(chan int)

    quit := make(chan int)

    go func() { //spin off the second function in order to let consume from c , so fibonaci can continue to work

        fmt.Println(<-c)    //read value from channel c

    }()

    //Try moving the statement that send value to channel quit in order to 

    //return function fibonacci

    quit <- 0   

    fibonacci(c, quit)

}

起初,我认为结果将与下面代码的结果相同


//function fibonacci is same with the first one

func fibonacci(c, quit chan int) {

    x, y := 0, 1

    for {

        select {

            case c <- x:  //sending value x into channel c

                x, y = y, x+y

            case <-quit:    //receive value from quit

                fmt.Println("quit")

        return

        }

    }

}


func main() {

    //create two channels

    c := make(chan int)

    quit := make(chan int)

    go func() { //spin off the second function in order to let consume from c , so fibonaci can continue to work

        fmt.Println(<-c)    //read value from channel c

        quit <- 0 //CHANGE: move the statement inside the closure function 

    }()


    fibonacci(c, quit)

}

输出是


0

quit

您能解释一下执行第一个示例时死锁的根本原因是什么吗?在go例程中发送值退出通道与在主线程中发送值退出通道有什么区别?


感谢你们。


慕田峪7331174
浏览 104回答 1
1回答

宝慕林4294392

该quit通道是无缓冲通道。在发送和接收 goroutine 都准备好之前,无缓冲通道上的通信不会继续。该语句quit <- 0在应用程序执行函数以接收值之前阻塞。接收 Goroutine 永远不会准备好通过关闭通道修复:c := make(chan int)quit := make(chan int)go func() {&nbsp; &nbsp; fmt.Println(<-c)}()close(quit)fibonacci(c, quit)...或者通过缓冲通道c := make(chan int, 1) // <- note size 1quit := make(chan int)go func() {&nbsp;&nbsp; &nbsp; fmt.Println(<-c)&nbsp;}()quit <- 0&nbsp; &nbsp;fibonacci(c, quit)在这种情况下,fibonacci将在产生值之前退出。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go