1 回答
TA貢獻1836條經驗 獲得超5個贊
分拆出來的函數如下所示(包括go前面的 和調用它的括號):
go func() {
for v := range c1 {
func(v2 int) {
c2 <- timeConsumingWork(v2)
}(v)
}
wg.Done()
}()
這段代碼有點奇怪和離奇。讓我們進一步縮小它,丟棄wg.Done并只保留for循環本身:
for v := range c1 {
func(v2 int) {
c2 <- timeConsumingWork(v2)
}(v)
}
有一個內部未命名的函數在這里非常沒用;我們可以在不改變程序行為的情況下丟棄它,得到:
for v := range c1 {
c2 <- timeConsumingWork(v)
}
這最后是一個簡單的循環?,F在的一個關鍵問題是:您期望從這個循環中進行多少次迭代? 注意:它不一定是任何常數?;蛟S更好的方式來表達這個問題是:這個循環什么時候結束?
for循環讀取一個通道。這種循環在從通道讀取指示沒有更多數據時結束,即通道已關閉且其隊列為空。(請參閱循環的 Go 規范部分for。)
所以這個最里面的循環,for v := range c1直到通道c1關閉并且隊列中沒有更多數據時才會終止。該頻道是使用以下內容創建的:
c1 := make(chan int)
所以它沒有隊列,所以我們甚至不需要考慮這一點:它在 aclose(c1)關閉它后終止。 您現在應該尋找一個closecloses c1。
我們的近在哪里?
這是關閉的地方c1:
func populate(c chan int) {
for i := 0; i < 100; i++ {
c <- i
}
close(c)
}
我們稱之為 withc1作為它的參數,所以它的 final close(c)closes c1。現在你可以問:我們什么時候接到這個close電話? 答案很明顯:i >= 100在循環之后,即,在我們將 100 個值(分別從 0 到 99)發送到 channel 之后c1。
什么fanOutIn是剝離 10 個 goroutine。10 個 goroutine 中的每一個都運行我上面引用的第一個匿名函數。該匿名函數有一個循環,運行次數不定,一直重復直到通道c1關閉。循環中的每次行程都會獲取通道的值,因此最初,如果十個 goroutine 都設法在有任何可用值之前啟動,那么所有十個 goroutine 都將等待值。
當生產者函數將一個值放入通道時,十個等待的 goroutine 中的一個將獲取它并開始使用它。如果該 goroutine 需要很長時間才能回到自己for循環的頂部,則另一個 goroutine 將獲取下一個生成的值。所以這里發生的情況是,多達 10 個生成的值通過通道傳播到多達 10 個 goroutine。1 這些(最多 10 個)goroutine 中的每一個都花費了一些重要的時間來使用它的值,然后將最終產品值發送到通道c2并返回到它自己的無限for循環的頂部。
只有當生產者關閉了它的通道c(這里是我們的c1)時,十個 goroutine 才會看到一個關閉的通道空隊列,從而允許它們退出for循環。當他們退出他們的for循環時,他們每個人都會調用wg.Done()(一次)并終止。
因此,一旦close(c1)發生(通過close(c)in populate),最終所有十個匿名 goroutine 都將調用wg.Done(). 屆時,wg.Wait()infanOutIn將返回。這將調用close(c2)并從 中返回fanOutIn,同時終止該goroutine。
同時,在 中main,我們使用for v := range c2從通道中讀取c2。當十個 goroutine 中的任何一個for寫入值時,此循環將運行。c2只有當它自己關閉時它才會退出c2(它的隊列也必須是空的,但又c2是一個零長度隊列)。所以在關閉之前main不會繼續通過for循環,直到返回才會發生,直到發生十次調用才會發生,直到通道關閉才會發生。c2wg.Wait()wg.Done()c1
這意味著在調用之前main無法通過自己的for循環,并且只有在生成恰好 100 個值之后才會發生這種情況。populateclose(c)
- 1 回答
- 0 關注
- 171 瀏覽
添加回答
舉報
