Go語言學習之Go協程:WaitGroup
阿新 • • 發佈:2020-10-27
我們之前學習了協程和通道,裡面有很多例子,當時為了保證main goroutine在所有的goroutine都執行完畢後在退出,我們使用了time.Sleep這種方式
由於寫的demo都是很簡單的,sleep個1秒,我們感覺應該是夠用的
但是在實際開發中,我們無法預知,所有的goroutine需要多長時間才能執行完畢,sleep多了 主程式就會阻塞,sleep少了有的子協程的任務無法完成
我們今天來介紹一下 怎麼優雅的處理這種情況
1.使用通道來標記完成
通道可以實現多個協程間的通訊,那麼我們只需要定義一個通道,在任務完成後,往通道中寫入true,然後主協程中獲取到true,就認為子協程執行完畢
import "fmt" func main() { done := make(chan bool) //開一個協程去執行 go func() { for i := 0; i < 5; i++ { fmt.Println(i) } //執行完畢,往信道里寫入true done <- true }() //主協程中如果獲取到信道里時true 就退出 <-done }
輸出如下
0 1 2 3 4
2.使用WaitGroup
上面使用的方法,在單個協程或者協程數量比較少的時候不會有什麼問題,但在協程數多的時候,程式碼就會很複雜
更優雅的方式就是使用WaitGroup
WaitGroup只要例項化了就能用
var 例項名 sync.WaitGroup
例項化完成後,就可以使用它的幾個方法:
Add:初始值為0,你傳入的值會往計數器上加,這裡直接傳入子協程的數量
Done: 當某個子協程完成後,可以呼叫此方法,就會從計數器上減1,通常可以使用defer來呼叫
Wait: 阻塞當前協程,知道計數器的值歸0
舉一個例子
// Startup the EventRouter //這裡有一個協程, 所以計數器的值是1 wg.Add(1)
//協程 go func() { //defer的作用是在eventRouter.run函式執行完,在執行defer的語句,所以這裡就是程式執行完了,執行wg.Done()把計數器裡的值減1defer wg.Done() eventRouter.Run(stop) }() // Startup the Informer(s) glog.Infof("Starting shared Informer(s)") sharedInformers.Start(stop) //主協程一直呼叫wg.Wait()方法阻塞著,直到計數器的值為0在執行後面的程式碼 wg.Wait()
//執行這個程式碼的時候,說明計數器歸0了,wg.Wait失效,不會阻塞主協程了 glog.Warningf("Exiting main()") os.Exit(1)
上面使用通道的方法,在單個協程或者協程數少的時候,並不會有什麼問題,但在協程數多的時候,程式碼就會顯得非常複雜