简体   繁体   English

将值发送到 go 例程之外的通道时,Go 例程会死锁

[英]Go routines are deadlock when sending value to channel outside the go routines

I tried changing a little bit on the code when learning Go select statement in Golang tour: https://tour.golang.org/concurrency/5 .在 Golang tour 中学习 Go select 语句时,我尝试对代码进行一些更改: https ://tour.golang.org/concurrency/5。 However, i got issue:但是,我遇到了问题:

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

Here is the code i tried and got the issue这是我尝试并遇到问题的代码

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

At first, i thought that the result will be same with result of below code起初,我认为结果将与以下代码的结果相同

//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)
}

The output is输出是

0
quit

Can you please explain what's the root cause of deadlock when executing the first example?你能解释一下执行第一个例子时死锁的根本原因是什么吗? And what are differences when sending value to quit channel in the go routines with sending value to quit channel in the main thread.在 go 例程中发送值到退出通道与在主线程中发送值到退出通道有什么区别。

Thank you guys.谢谢你们。

The quit channel is an unbuffered channel. quit通道是一个无缓冲通道。 Communication on an unbuffered channel does not proceed until both a sending and receiving goroutine are ready.在发送和接收 goroutine 都准备好之前,无缓冲通道上的通信不会继续。 The statement quit <- 0 blocks before the application executes the function to receive the value.在应用程序执行函数以接收值之前,语句quit <- 0阻塞。 A receiving goroutine will never be ready接收 goroutine 永远不会准备好

Fix by closing the channel:通过关闭通道修复:

c := make(chan int)
quit := make(chan int)
go func() {
    fmt.Println(<-c)
}()
close(quit)
fibonacci(c, quit)

... or by making the channel buffered ...或通过使通道缓冲

c := make(chan int, 1) // <- note size 1
quit := make(chan int)
go func() { 
    fmt.Println(<-c) 
}()
quit <- 0   
fibonacci(c, quit)

In this scenario, fibonacci will quit before yielding a value.在这种情况下, fibonacci将在产生值之前退出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM