2 回答

TA貢獻1794條經驗 獲得超8個贊
您的main()
函數嘗試在所有通道上發送,并且僅一次性嘗試在單獨的并發 goroutine 中從這些通道中讀取數據。這是否成功取決于 goroutine 調度程序。如果非阻塞接收的安排f2()
早于發送main()
,那么后面的發送main()
將永遠阻塞(沒有人會再次嘗試接收ch2
)。
擺脫死鎖的一種方法是使用接收操作而不是非阻塞接收(在Go Playground上嘗試一下):
func f1() {
? ? <-ch1
? ? fmt.Println("ch1")
}
func f2() {
? ? <-ch2
? ? fmt.Println("ch2")
}
因此,無論何時main()
到達在這些通道上發送值的點,總會有一個接收器準備好繼續,因此不會main()
被卡住。
請注意,當main()
返回時,應用程序結束,它不會等待非主 goroutine 完成。因此您可能看不到ch1
并ch2
打印在控制臺上。
如果您的目的是在您的應用程序存在之前等待所有 goroutine 完成其工作,請使用sync.WaitGroup
它(在Go Playground上嘗試):
var ch1 = make(chan int)
var ch2 = make(chan int)
var wg sync.WaitGroup
func f1() {
? ? defer wg.Done()
? ? <-ch1
? ? fmt.Println("ch1")
}
func f2() {
? ? defer wg.Done()
? ? <-ch2
? ? fmt.Println("ch2")
}
func main() {
? ? wg.Add(1)
? ? go f1()
? ? wg.Add(1)
? ? go f2()
? ? ch1 <- 1
? ? ch2 <- 2
? ? wg.Wait()
}
另一種選擇是為通道提供 1 的緩沖區,這樣就可以在通道上發送 1 個值,而無需準備好從通道接收的接收器(在Go Playgroundmain()
上嘗試這個):
var?ch1?=?make(chan?int,?1) var?ch2?=?make(chan?int,?1)
有了這個,就可以在沒有和 的情況main()
下繼續,所以同樣,不能保證您會看到任何打印內容。f1()
f2()

TA貢獻2019條經驗 獲得超9個贊
這里使用的通道是無緩沖通道。
當主協程啟動時,它會創建兩個新的協程 f1 和 f2。
當執行 f1 或 f2 時,它將檢查通道中是否有值,否則它將打印默認消息并退出。
在理想情況下,通道將首先發布值,然后通過 goroutine 接收它
實際情況是 Goroutine 通過打印默認情況退出,但主 Goroutine 試圖在通道中發布值,但由于沒有接收器,它面臨死鎖情況。
消除了第一個示例中的死鎖,請參閱鏈接:https ://play.golang.org/p/6RuQQwC9JkA
但是,如果主例程退出,所有關聯的 goroutine 將被自動殺死。這就是為什么我們可以看到該值是任意打印的。
刪除了第二個示例中的死鎖,請參閱鏈接:https ://play.golang.org/p/yUmc_jjZMgV
sync.WaitGroup 正在使主 goroutine 等待,這就是為什么我們可以在每次程序執行時觀察到輸出。
- 2 回答
- 0 關注
- 164 瀏覽
添加回答
舉報