欧美亚洲中文,在线国自产视频,欧洲一区在线观看视频,亚洲综合中文字幕在线观看

      1. <dfn id="rfwes"></dfn>
          <object id="rfwes"></object>
        1. 站長(zhǎng)資訊網(wǎng)
          最全最豐富的資訊網(wǎng)站

          分析Golang的WaitGroup陷阱并解決問題

          本文由go語言教程欄目給大家介紹關(guān)于Golang的WaitGroup陷阱,希望對(duì)需要的朋友有所幫助!

          sync.WaitGroup是并發(fā)環(huán)境中,一個(gè)相當(dāng)常用的數(shù)據(jù)結(jié)構(gòu),用來等待所有協(xié)程的結(jié)束,在寫代碼的時(shí)候都是按著例子的樣子寫的,也沒用深究過它的使用。前幾日想著能不能在協(xié)程中執(zhí)行Add()函數(shù),答案是不能,這里介紹下。

          陷阱在WaitGroup的3個(gè)函數(shù)的調(diào)用順序上。先回顧下3個(gè)函數(shù)的功能:

          1. Add(delta int):給計(jì)數(shù)器增加delta,比如啟動(dòng)1個(gè)協(xié)程就增加1。
          2. Done():協(xié)程退出前執(zhí)行,把計(jì)數(shù)器減1。
          3. Wait():阻塞等待計(jì)數(shù)器為0。

          考一考

          下面的程序是創(chuàng)建了協(xié)程father,然后father協(xié)程創(chuàng)建了10個(gè)子協(xié)程,main函數(shù)等待所有協(xié)程結(jié)束后退出,看看下面代碼有沒有什么問題?

          package main  import (     "fmt"     "sync" )  func father(wg *sync.WaitGroup) {     wg.Add(1)     defer wg.Done()      fmt.Printf("fathern")     for i := 0; i < 10; i++ {         go child(wg, i)     } }  func child(wg *sync.WaitGroup, id int) {     wg.Add(1)     defer wg.Done()      fmt.Printf("child [%d]n", id) }  func main() {     var wg sync.WaitGroup     go father(&wg)      wg.Wait()     log.Printf("main: father and all chindren exit") }

          發(fā)現(xiàn)問題了嗎?如果沒有看下面的運(yùn)行結(jié)果:main函數(shù)在子協(xié)程結(jié)束前就開始結(jié)束了。

          father main: father and all chindren exit child [9] child [0] child [4] child [7] child [8]

          陷阱分析

          產(chǎn)生以上問題的原因在于,創(chuàng)建協(xié)程后在協(xié)程內(nèi)才執(zhí)行Add()函數(shù),而此時(shí)Wait()函數(shù)可能已經(jīng)在執(zhí)行,甚至Wait()函數(shù)在所有Add()執(zhí)行前就執(zhí)行了,Wait()執(zhí)行時(shí)立馬就滿足了WaitGroup的計(jì)數(shù)器為0,Wait結(jié)束,主程序退出,導(dǎo)致所有子協(xié)程還沒完全退出,main函數(shù)就結(jié)束了。

          正確的做法

          Add函數(shù)一定要在Wait函數(shù)執(zhí)行前執(zhí)行,這在Add函數(shù)的文檔中就提示了: Note that calls with a positive delta that occur when the counter is zero must happen before a Wait.。

          如何確保Add函數(shù)一定在Wait函數(shù)前執(zhí)行呢?在協(xié)程情況下,我們不能預(yù)知協(xié)程中代碼執(zhí)行的時(shí)間是否早于Wait函數(shù)的執(zhí)行時(shí)間,但是,我們可以在分配協(xié)程前就執(zhí)行Add函數(shù),然后再執(zhí)行Wait函數(shù),以此確保。

          下面是修改后的程序,以及輸出結(jié)果。

          package main  import (     "fmt"     "sync" )  func father(wg *sync.WaitGroup) {     defer wg.Done()      fmt.Printf("fathern")     for i := 0; i < 10; i++ {         wg.Add(1)         go child(wg, i)     } }  func child(wg *sync.WaitGroup, id int) {     defer wg.Done()     fmt.Printf("child [%d]n", id) }  func main() {     var wg sync.WaitGroup     wg.Add(1)     go father(&wg)      wg.Wait()     fmt.Println("main: father and all chindren exit") }
          father child [9] child [7] child [8] child [1] child [4] child [5] child [2] child [6] child [0] child [3] main: father and all chindren exit

          贊(0)
          分享到: 更多 (0)
          網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)