1 回答

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