做網(wǎng)站需要注冊商標(biāo)是幾類手機(jī)優(yōu)化大師
WaitGroup
為了保證 main goroutine 在所有的 goroutine 都執(zhí)行完畢后再退出,前面使用了 time.Sleep 這種簡單的方式。
由于寫的 demo 都是比較簡單的, sleep 個(gè) 1 秒,我們主觀上認(rèn)為是夠用的。
但在實(shí)際開發(fā)中,開發(fā)人員是無法預(yù)知,所有的 goroutine 需要多長的時(shí)間才能執(zhí)行完畢,sleep 多了,主程序就阻塞了, sleep 少了,有的子協(xié)程的任務(wù)就沒法完成。
因此,使用time.Sleep 是一種極不推薦的方式,今天主要就要來介紹 一下如何優(yōu)雅的處理這種情況。
1. 使用信道來標(biāo)記完成
“不要通過共享內(nèi)存來通信,要通過通信來共享內(nèi)存”
學(xué)習(xí)了信道后,我們知道,信道可以實(shí)現(xiàn)多個(gè)協(xié)程間的通信,那么我們只要定義一個(gè)信道,在任務(wù)完成后,往信道中寫入true,然后在主協(xié)程中獲取到true,就認(rèn)為子協(xié)程已經(jīng)執(zhí)行完畢。
import "fmt"func main() {done := make(chan bool)go func() {for i := 0; i < 5; i++ {fmt.Println(i)}done <- true}()<-done
}
2. 使用 WaitGroup
上面使用信道的方法,在單個(gè)協(xié)程或者協(xié)程數(shù)少的時(shí)候,并不會有什么問題,但在協(xié)程數(shù)多的時(shí)候,代碼就會顯得非常復(fù)雜。
那么有沒有一種更加優(yōu)雅的方式呢?
有,這就要說到 sync包 提供的 WaitGroup 類型。
WaitGroup 你只要實(shí)例化了就能使用
var 實(shí)例名 sync.WaitGroup
實(shí)例化完成后,就可以使用它的幾個(gè)方法:
-
Add:初始值為0,你傳入的值會往計(jì)數(shù)器上加,這里直接傳入你子協(xié)程的數(shù)量
-
Done:當(dāng)某個(gè)子協(xié)程完成后,可調(diào)用此方法,會從計(jì)數(shù)器上減一,通??梢允褂?defer 來調(diào)用。
-
Wait:阻塞當(dāng)前協(xié)程,直到實(shí)例里的計(jì)數(shù)器歸零。
eg:
import ("fmt""sync"
)func worker(x int,wg *sync.WaitGroup){defer wg.Done()for i := 0;i<5; i++{fmt.Printf("worker %d: %d\n",x,i);}
}func main() {var wg sync.WaitGroupwg.Add(2)go worker(1,&wg)go worker(2,&wg)wg.Wait()
}