golang sync.WaitGroup 用法


執行一個簡單協程
  package main

  import (
  "fmt"
  "time"
  )

  func main(){
    for i := 0; i < 100 ; i++{
    go fmt.Println(i)
    }
    time.Sleep(time.Second)
  }

分析:

為什么會有sleep 呢, 主線程為了等待goroutine都運行完畢, 不得不在程序的末尾使用time.Sleep()來睡眠一段時間, 等待 其他線程充分運行 。對於簡單的代碼100 個for 循環可以在1秒內運行完但是實際的場景中大部分是1秒不夠的, 而且大部分的時間 我們都無法預測for 循環內的代碼運行時間的長短, 這個時候就不能使用time.sleep() 來完成等待操作了。

使用管道來 完成 操作

  func main() {
    c := make(chan bool, 100)
    for i := 0; i < 100; i++ {
    go func(i int) {
    fmt.Println(i)
    c <- true
    }(i)
    }

    for i := 0; i < 100; i++ {
    <-c
    }
  }
通道是可以完全達到目的的
但是在這里 管道會 有些大材小用,因為它被設計出來不僅僅只是在這里用作簡單的同步處理,在這里使用管道實際上是不合適的。而且假設我們有一萬、十萬甚至更多的for循環,也要申請同樣數量大小的管道出來,對內存也是不小的開銷

對於這種情況, go 語言中有一個其他的工具 sync.WaitGroup 能更加方便的達到這個目的。
WaitGroup對象內部有個計時器, 最初從0 開始, 他有3個方法 Add() , Done(), Wait()用來控制計數器的數量。 Add(n) 把計數器設置成n, Done() 每次把計數器-1, wait() 會阻塞代碼的運行, 直到計數器的值減為0

將上面代碼修改:

  func main() {
    wg := sync.WaitGroup{}
    wg.Add(100)
    for i := 0; i < 100; i++ {
    go func(i int) {
    fmt.Println(i)
    wg.Done()
    }(i)
    }
  wg.Wait()
  }

這里計數器設置為 100 每個for 循環運行完畢都把計數器減1 主函數中使用Wait() 一直阻塞, 直到wg為0 也就是所有的 100 個for 循環都運行完畢, 相對於使用 管道來說 WaitGroup輕巧了很多。

注意的事項 使用waitGroup
計數器不能為負
我們不能使用Add()給wg 設置一個負值 否則代碼會報錯

  panic: sync: negative WaitGroup counter

    goroutine 1 [running]:
    sync.(*WaitGroup).Add(0xc042008230, 0xffffffffffffff9c)
    D:/Go/src/sync/waitgroup.go:75 +0x1d0
    main.main()
    D:/code/go/src/test-src/2-Package/sync/waitgroup/main.go:10 +0x54
同樣使用done() 也要特別注意不能把計數器的值設置為負值

WaitGroup 對象不是一個引用類型, 在通過函數傳值的時候需要使用地址;

注意:值類型包括基本數據類型,int,float,bool,string,以及數組和結構體(struct)。注意:指針也是值類型;sync.WaitGroup 對象是值類型,不是一個引用類型
值類型變量聲明后,不管是否已經賦值,編譯器為其分配內存,此時該值存儲於棧上。

  func main() {
    wg := sync.WaitGroup{}  //所以這句可以換成 var wg sync.WaitGroup;
    wg.Add(100)
    for i := 0; i < 100; i++ {
      go f(i, &wg)
    }
       wg.Wait()
  }

  // 一定要通過指針傳值,不然進程會進入死鎖狀態
  func f(i int, wg *sync.WaitGroup) {
  fmt.Println(i)
  wg.Done()
  }


原文鏈接:https://blog.csdn.net/yangxiaodong88/article/details/96309601


免責聲明!

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



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