主頁 > 知識庫 > Golang中的sync包的WaitGroup操作

Golang中的sync包的WaitGroup操作

熱門標(biāo)簽:壽光微信地圖標(biāo)注 評價高的400電話辦理 外呼系統(tǒng)顯本地手機(jī)號 excel地圖標(biāo)注分布數(shù)據(jù) 電話機(jī)器人軟件免費(fèi) 阿克蘇地圖標(biāo)注 涿州代理外呼系統(tǒng) 百度地圖標(biāo)注后傳給手機(jī) 外呼系統(tǒng)用什么卡

sync的waitgroup功能

WaitGroup

使用多線程時,進(jìn)行等待多線程執(zhí)行完畢后,才可以結(jié)束函數(shù),有兩個選擇

channel

waitgroup

首先使用channel

func add (n *int , isok chan bool){
	for i :=0 ;i 1000 ; i ++ {
		*n = *n + 1
	}
	isok - true
}
func main () {
	var ok = make(chan bool , 2)
	var i,u = 0,0
	go add(i , ok)
	go add(i , ok)
	for - ok {
		u++
		if u == 2 {
			break
		}
	}
	fmt.Println(i)
}

但是,如果線程一旦增多,就會導(dǎo)致代碼冗余,增加負(fù)擔(dān),可以使用sync.WaitGroup包

func add (n *int , wait *sync.WaitGroup) {
 for i := 0 ; i 1000 ; i ++ {
  *n = *n + 1
 }
 defer wait.Done()
}
func main () {
  var wait sync.WaitGroup
 var i = 0
 wait.Add(2)
  go add(i , wait)
 go add(i , wait)
 wait.Wait()
 fmt.Println(i)
 }

仿sync.WaitGroup功能

type Wait struct {//創(chuàng)建一個結(jié)構(gòu)體
 Num int//線程的個數(shù)
 ok chan bool//線程與函數(shù)通信的管道
}
func (t *Wait) Add (n int){//初始化線程個數(shù)
 t.Num = n
 t.ok = make(chan bool , n)
}
func (t *Wait) Done (){//執(zhí)行完一個線程之后,執(zhí)行的函數(shù),每執(zhí)行完一個線程,調(diào)用函數(shù),使用通信管道進(jìn)行傳輸一個true
 t.ok - true
}
func (t *Wait) Wait () {//等待函數(shù),每次管道中放入一個true,說明,執(zhí)行完一個線程,t.Num--,如果等于0說明所有線程執(zhí)行結(jié)束
 for - t.ok {
  t.Num--
  if t.Num == 0 {
   break
  }
 }
}

補(bǔ)充:Golang的WaitGroup陷阱

sync.WaitGroup是并發(fā)環(huán)境中,一個相當(dāng)常用的數(shù)據(jù)結(jié)構(gòu),用來等待所有協(xié)程的結(jié)束,在寫代碼的時候都是按著例子的樣子寫的,也沒用深究過它的使用。前幾日想著能不能在協(xié)程中執(zhí)行Add()函數(shù),答案是不能,這里介紹下。

陷阱在WaitGroup的3個函數(shù)的調(diào)用順序上。先回顧下3個函數(shù)的功能:

Add(delta int):給計數(shù)器增加delta,比如啟動1個協(xié)程就增加1。

Done():協(xié)程退出前執(zhí)行,把計數(shù)器減1。

Wait():阻塞等待計數(shù)器為0。

考一考

下面的程序是創(chuàng)建了協(xié)程father,然后father協(xié)程創(chuàng)建了10個子協(xié)程,main函數(shù)等待所有協(xié)程結(jié)束后退出,看看下面代碼有沒有什么問題?

package main 
import (
    "fmt"
    "sync"
)
 
func father(wg *sync.WaitGroup) {
    wg.Add(1)
    defer wg.Done()
 
    fmt.Printf("father\n")
    for i := 0; i  10; i++ {
        go child(wg, i)
    }
}
 
func child(wg *sync.WaitGroup, id int) {
    wg.Add(1)
    defer wg.Done()
 
    fmt.Printf("child [%d]\n", id)
}
 
func main() {
    var wg sync.WaitGroup
    go father(wg)
 
    wg.Wait()
    log.Printf("main: father and all chindren exit")
}

發(fā)現(xiàn)問題了嗎?如果沒有看下面的運(yùn)行結(jié)果:main函數(shù)在子協(xié)程結(jié)束前就開始結(jié)束了。

father
main: father and all chindren exit
child [9]
child [0]
child [4]
child [7]
child [8]

陷阱分析

產(chǎn)生以上問題的原因在于,創(chuàng)建協(xié)程后在協(xié)程內(nèi)才執(zhí)行Add()函數(shù),而此時Wait()函數(shù)可能已經(jīng)在執(zhí)行,甚至Wait()函數(shù)在所有Add()執(zhí)行前就執(zhí)行了,Wait()執(zhí)行時立馬就滿足了WaitGroup的計數(shù)器為0,Wait結(jié)束,主程序退出,導(dǎo)致所有子協(xié)程還沒完全退出,main函數(shù)就結(jié)束了。

正確的做法

Add函數(shù)一定要在Wait函數(shù)執(zhí)行前執(zhí)行,這在Add函數(shù)的文檔中就提示了: Note that calls with a positive delta that occur when the counter is zero must happen before a Wait.。

如何確保Add函數(shù)一定在Wait函數(shù)前執(zhí)行呢?在協(xié)程情況下,我們不能預(yù)知協(xié)程中代碼執(zhí)行的時間是否早于Wait函數(shù)的執(zhí)行時間,但是,我們可以在分配協(xié)程前就執(zhí)行Add函數(shù),然后再執(zhí)行Wait函數(shù),以此確保。

下面是修改后的程序,以及輸出結(jié)果。

package main 
import (
    "fmt"
    "sync"
)
 
func father(wg *sync.WaitGroup) {
    defer wg.Done()
 
    fmt.Printf("father\n")
    for i := 0; i  10; i++ {
        wg.Add(1)
        go child(wg, i)
    }
}
 
func child(wg *sync.WaitGroup, id int) {
    defer wg.Done()
    fmt.Printf("child [%d]\n", id)
}
 
func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    go father(wg)
 
    wg.Wait()
    fmt.Println("main: father and all chindren exit")
}
father
child [9]
child [7]
child [8]
child [1]
child [4]
child [5]
child [2]
child [6]
child [0]
child [3]
main: father and all chindren exit

以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。如有錯誤或未考慮完全的地方,望不吝賜教。

您可能感興趣的文章:
  • 解決Golang 中使用WaitGroup的那點(diǎn)坑
  • 在golang中使用Sync.WaitGroup解決等待的問題
  • Golang中的sync.WaitGroup用法實(shí)例
  • Golang標(biāo)準(zhǔn)庫syscall詳解(什么是系統(tǒng)調(diào)用)
  • Golang的os標(biāo)準(zhǔn)庫中常用函數(shù)的整理介紹
  • Golang 標(biāo)準(zhǔn)庫 tips之waitgroup詳解

標(biāo)簽:欽州 吐魯番 雞西 銅川 梅河口 蘭州 汕頭 重慶

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Golang中的sync包的WaitGroup操作》,本文關(guān)鍵詞  Golang,中的,sync,包的,WaitGroup,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《Golang中的sync包的WaitGroup操作》相關(guān)的同類信息!
  • 本頁收集關(guān)于Golang中的sync包的WaitGroup操作的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章