27. 學習 Go 協程:WaitGroup

Hi,你們好,我是明哥。git

在本身學習 Golang 的這段時間裏,我寫了詳細的學習筆記放在個人我的微信公衆號 《Go編程時光》,對於 Go 語言,我也算是個初學者,所以寫的東西應該會比較適合剛接觸的同窗,若是你也是剛學習 Go 語言,不防關注一下,一塊兒學習,一塊兒成長。github

個人在線博客:golang.iswbm.com 個人 Github:github.com/iswbm/GolangCodingTimegolang


在前兩篇文章裏,咱們學習了 協程信道 的內容,裏面有不少例子,當時爲了保證 main goroutine 在全部的 goroutine 都執行完畢後再退出,我使用了 time.Sleep 這種簡單的方式。編程

因爲寫的 demo 都是比較簡單的, sleep 個 1 秒,咱們主觀上認爲是夠用的。微信

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

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

1. 使用信道來標記完成

「不要經過共享內存來通訊,要經過通訊來共享內存」code

學習了信道後,咱們知道,信道能夠實現多個協程間的通訊,那麼咱們只要定義一個信道,在任務完成後,往信道中寫入true,而後在主協程中獲取到true,就認爲子協程已經執行完畢。cdn

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。。


相關文章
相關標籤/搜索