package mainimport ( "fmt" "math/rand" "time")func boring(msg string) <-chan string { // Returns receive-only channel of strings. c := make(chan string) go func() { // We launch the goroutine from inside the function. for i := 0; ; i++ { c <- fmt.Sprintf("%s %d", msg, i) time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond) } }() return c // Return the channel to the caller.}func fanIn(input1, input2 <-chan string) <-chan string { c := make(chan string) go func() { for { c <- <-input1 } }() go func() { for { c <- <-input2 } }() return c}func main() { c := fanIn(boring("Joe"), boring("Ann")) for i := 0; i < 10; i++ { fmt.Println(<-c) } fmt.Println("You're both boring; I'm leaving.")}這是 Rob Pike 關于Go 并發模式的演講中的一個示例。我理解扇入模式背后的想法,并且我理解在 main 中打印消息的順序是不確定的:我們只打印 10 條結果證明已經準備好的消息。然而,我不完全理解的是調用的順序以及什么阻塞了什么。僅使用無緩沖通道,因此根據文檔,無緩沖通道會阻止發送方。該boring函數啟動一個 goroutine,將字符串發送到c返回的無緩沖通道。如果我理解正確,這個內部 goroutine 會啟動但不會阻塞boring。它可以立即將通道返回main給fanIn函數。但fanIn做幾乎相同的事情:它從輸入通道接收值并將它們發送到返回的自己的通道。阻塞是如何發生的?在這種情況下是什么阻止了什么?一個示意性的解釋將是完美的,因為老實說,即使我有一個直觀的理解,我也想了解它背后的確切邏輯。我的直觀理解是,每次發送都boring阻塞,直到接收到值fanIn,但隨后該值立即發送到另一個通道,因此它被阻塞,直到接收到值main。粗略地說,這三個功能由于使用了通道而緊密地綁定在一起
1 回答

30秒到達戰場
TA貢獻1828條經驗 獲得超6個贊
阻塞是如何發生的?在這種情況下是什么阻止了什么?
如果另一側沒有相應的接收操作(或者如果通道是nil
,則成為沒有接收器的情況),則無緩沖通道上的每個發送都會阻塞。
考慮到main
調用boring
和fanIn
順序發生的情況。特別是這一行:
c := fanIn(boring("Joe"), boring("Ann"))
有評估順序:
boring("Joe")
boring("Ann")
fanIn
中的發送操作并在 中boring("Joe")
具有boring("Ann")
相應的接收操作fanIn
,因此它們會阻塞直到fanIn
運行。因此boring
產生了自己的 goroutine 以確保它在fanIn
可以開始接收之前返回通道。
中的發送操作在 中fanIn
具有相應的接收操作main
,因此它們將阻塞直到fmt.Println(<-c)
運行。因此fanIn
產生它自己的 goroutine(s) 以確保它在main
可以開始接收它之前返回輸出通道。
finallymain
的執行讓fmt.Println(<-c)
一切都開始運轉。接收c
解除阻塞c <- <-input[1|2]
和接收<-input[1|2]
解除阻塞c <- fmt.Sprintf("%s %d", msg, i)
。
如果去掉 中的接收操作main
,main
仍然可以繼續執行,程序馬上退出,不會發生死鎖。
- 1 回答
- 0 關注
- 145 瀏覽
添加回答
舉報
0/150
提交
取消