這是我的全部 Go 代碼!讓我困惑的是case balances <- balance:沒有發生。我不知道為什么?
package main
import (
"fmt"
)
func main() {
done := make(chan int)
var balance int
balances := make(chan int)
balance = 1
go func() {
fmt.Println(<-balances)
done <- 1
}()
select {
case balances <- balance:
fmt.Println("done case")
default:
fmt.Println("default case")
}
<-done
}
default case
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/tmp/sandbox575832950/prog.go:29 0x13d
goroutine 18 [chan receive]:
main.main.func1()
/tmp/sandbox575832950/prog.go:17 0x38
created by main.main
/tmp/sandbox575832950/prog.go:16 0x97
uj5u.com熱心網友回復:
主協程在匿名協程函式執行從 接收之前執行選擇balances。主 goroutine 執行 select 中的 default 子句,因為在 上沒有準備好的接收器balances。主 goroutine 繼續接收done.
goroutine 在接收時阻塞,balances因為沒有發送者。Main 通過采用默認子句繼續發送。
done由于沒有發送方,主 goroutine 在接收時阻塞。goroutine 在從 接收時被阻塞balances。
通過將 select 陳述句替換為balances <- balance. 該default條款導致了問題。當default該類被洗掉時,選擇中剩余的所有內容都將發送到balances.
uj5u.com熱心網友回復:
由于并發,無法保證 goroutine 會在select. 我們可以通過向 goroutine 添加列印來看到這一點。
go func() {
fmt.Println("Here")
fmt.Println(<-balances)
done <- 1
}()
$ go run test.go
default case
Here
fatal error: all goroutines are asleep - deadlock!
...
如果選擇先運行,balances <- balance則會阻塞;balances沒有緩沖區,也沒有任何東西試圖從中讀取。case balances <- balance會阻塞所以select跳過它并執行它的默認值。
然后 goroutine 運行并阻止讀取balances。同時主要代碼塊讀取done。僵局。
您可以通過從選擇中洗掉默認情況并允許它阻塞直到準備好寫入余額來解決此問題。
select {
case balances <- balance:
fmt.Println("done case")
}
或者您可以添加一個緩沖區,balances以便在讀取之前可以將其寫入。然后case balances <- balance不阻塞。
balances := make(chan int, 1)
uj5u.com熱心網友回復:
讓我困惑的是 case balances <- balance: did not發生
具體來說:這是因為select有一個default案例。
每當您使用 來創建新的 goroutine 時go ...(),都無法保證接下來是呼叫的 goroutine 還是被呼叫的 goroutine 會運行。
在實踐中,呼叫 goroutine 中的下一個陳述句很可能會在下一個執行(沒有特別好的理由停止它)。當然,我們應該撰寫始終正常運行的程式,而不僅僅是某些、大多數甚至幾乎所有時間!并發編程go ...()就是同步 goroutines,以便必須發生預期的行為。如果使用得當,渠道可以做到這一點。
我認為余額通道可以接收資料
它是一個無緩沖通道,因此如果有人正在讀取它,它可以接收資料。否則,對通道的寫入將被阻塞。這讓我們回到select.
由于您提供了一個default案例,很可能呼叫的 goroutinego ...()將繼續執行,并且select不能立即選擇不同的案例,將選擇default. 因此,被呼叫的 goroutine 不太可能balances在主 goroutine 已經開始嘗試寫入它之前準備好讀取,失敗并繼續處理這個default案例。
您可以通過從選擇中洗掉默認情況并允許它阻塞直到準備好寫入余額來解決此問題。
正如@Schwern 指出的那樣,您當然可以。但重要的是您要了解您不一定需要select使用頻道。而不是只有一個案例的選擇,你可以只寫
balances <- balance
fmt.Println("done")
select在這種情況下不需要,default對您不利,否則只有一種情況,因此不需要select. 您希望主函式在該通道上阻塞。
您可以向余額添加緩沖區,以便在讀取之前可以將其寫入。
當然。但同樣,重要的是要理解,在發送方和接收方都準備好通信之前,通道可能會阻塞發送方和接收方,這是通道的有效、有用和常見用途。無緩沖通道不是問題的原因 -default為您的選擇提供一個案例,從而為意外行為提供一條路徑是原因。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/347805.html
