簡體   English   中英

將值發送到 go 例程之外的通道時,Go 例程會死鎖

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

在 Golang tour 中學習 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 例程中發送值到退出通道與在主線程中發送值到退出通道有什么區別。

謝謝你們。

quit通道是一個無緩沖通道。 在發送和接收 goroutine 都准備好之前,無緩沖通道上的通信不會繼續。 在應用程序執行函數以接收值之前,語句quit <- 0阻塞。 接收 goroutine 永遠不會准備好

通過關閉通道修復:

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

...或通過使通道緩沖

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

在這種情況下, fibonacci將在產生值之前退出。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM