27. 學習 Go 協程:WaitGroup


Hi,大家好,我是明哥。

在自己學習 Golang 的這段時間里,我寫了詳細的學習筆記放在我的個人微信公眾號 《Go編程時光》,對於 Go 語言,我也算是個初學者,因此寫的東西應該會比較適合剛接觸的同學,如果你也是剛學習 Go 語言,不防關注一下,一起學習,一起成長。

我的在線博客:http://golang.iswbm.com
我的 Github:github.com/iswbm/GolangCodingTime


在前兩篇文章里,我們學習了 協程信道 的內容,里面有很多例子,當時為了保證 main goroutine 在所有的 goroutine 都執行完畢后再退出,我使用了 time.Sleep 這種簡單的方式。

由於寫的 demo 都是比較簡單的, sleep 個 1 秒,我們主觀上認為是夠用的。

但在實際開發中,開發人員是無法預知,所有的 goroutine 需要多長的時間才能執行完畢,sleep 多了吧主程序就阻塞了, sleep 少了吧有的子協程的任務就沒法完成。

因此,使用time.Sleep 是一種極不推薦的方式,今天主要就要來介紹 一下如何優雅的處理這種情況。

1. 使用信道來標記完成

“不要通過共享內存來通信,要通過通信來共享內存”

學習了信道后,我們知道,信道可以實現多個協程間的通信,那么我們只要定義一個信道,在任務完成后,往信道中寫入true,然后在主協程中獲取到true,就認為子協程已經執行完畢。

import "fmt"

func main() {
	done := make(chan bool)
	go func() {
		for i := 0; i < 5; i++ {
			fmt.Println(i)
		}
		done <- true
	}()
	<-done
}

輸出如下

0
1
2
3
4

2. 使用 WaitGroup

上面使用信道的方法,在單個協程或者協程數少的時候,並不會有什么問題,但在協程數多的時候,代碼就會顯得非常復雜,有興趣可以自己嘗試一下。

那么有沒有一種更加優雅的方式呢?

有,這就要說到 sync包 提供的 WaitGroup 類型。

WaitGroup 你只要實例化了就能使用

var 實例名 sync.WaitGroup 

實例化完成后,就可以使用它的幾個方法:

  • Add:初始值為0,你傳入的值會往計數器上加,這里直接傳入你子協程的數量
  • Done:當某個子協程完成后,可調用此方法,會從計數器上減一,通常可以使用 defer 來調用。
  • Wait:阻塞當前協程,直到實例里的計數器歸零。

舉一個例子:

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.WaitGroup

	wg.Add(2)
	go worker(1, &wg)
	go worker(2, &wg)

	wg.Wait()
}

輸出如下

worker 2: 0
worker 2: 1
worker 2: 2
worker 2: 3
worker 2: 4
worker 1: 0
worker 1: 1
worker 1: 2
worker 1: 3
worker 1: 4

以上就是我們在 Go 語言中實現一主多子的協程協作方式,推薦使用 sync.WaitGroup。。

系列導讀

01. 開發環境的搭建(Goland & VS Code)

02. 學習五種變量創建的方法

03. 詳解數據類型:****整形與浮點型

04. 詳解數據類型:byte、rune與string

05. 詳解數據類型:數組與切片

06. 詳解數據類型:字典與布爾類型

07. 詳解數據類型:指針

08. 面向對象編程:結構體與繼承

09. 一篇文章理解 Go 里的函數

10. Go語言流程控制:if-else 條件語句

11. Go語言流程控制:switch-case 選擇語句

12. Go語言流程控制:for 循環語句

13. Go語言流程控制:goto 無條件跳轉

14. Go語言流程控制:defer 延遲調用

15. 面向對象編程:接口與多態

16. 關鍵字:make 和 new 的區別?

17. 一篇文章理解 Go 里的語句塊與作用域

18. 學習 Go 協程:goroutine

19. 學習 Go 協程:詳解信道/通道

20. 幾個信道死鎖經典錯誤案例詳解

21. 學習 Go 協程:WaitGroup

22. 學習 Go 協程:互斥鎖和讀寫鎖

23. Go 里的異常處理:panic 和 recover

24. 超詳細解讀 Go Modules 前世今生及入門使用

25. Go 語言中關於包導入必學的 8 個知識點

26. 如何開源自己寫的模塊給別人用?

27. 說說 Go 語言中的類型斷言?

28. 這五點帶你理解Go語言的select用法



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM