亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何在 Go Concurrency Patterns fan-in 示例中推理 Go 通道阻塞?

如何在 Go Concurrency Patterns fan-in 示例中推理 Go 通道阻塞?

Go
MMTTMM 2022-10-31 15:33:43
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調用boringfanIn順序發生的情況。特別是這一行:

c := fanIn(boring("Joe"), boring("Ann"))

有評估順序:

  1. boring("Joe")

  2. boring("Ann")

  3. 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)。

如果去掉 中的接收操作mainmain仍然可以繼續執行,程序馬上退出,不會發生死鎖。


查看完整回答
反對 回復 2022-10-31
  • 1 回答
  • 0 關注
  • 145 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號