最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang中的sync包的WaitGroup操作

 更新時(shí)間:2021年04月27日 09:35:53   作者:鹿灝楷silves  
這篇文章主要介紹了Golang中的sync包的WaitGroup操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧

sync的waitgroup功能

WaitGroup

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

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)
}

但是,如果線程一旦增多,就會(huì)導(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)建一個(gè)結(jié)構(gòu)體
 Num int//線程的個(gè)數(shù)
 ok chan bool//線程與函數(shù)通信的管道
}
func (t *Wait) Add (n int){//初始化線程個(gè)數(shù)
 t.Num = n
 t.ok = make(chan bool , n)
}
func (t *Wait) Done (){//執(zhí)行完一個(gè)線程之后,執(zhí)行的函數(shù),每執(zhí)行完一個(gè)線程,調(diào)用函數(shù),使用通信管道進(jìn)行傳輸一個(gè)true
 t.ok <- true
}
func (t *Wait) Wait () {//等待函數(shù),每次管道中放入一個(gè)true,說明,執(zhí)行完一個(gè)線程,t.Num--,如果等于0說明所有線程執(zhí)行結(jié)束
 for <- t.ok {
  t.Num--
  if t.Num == 0 {
   break
  }
 }
}

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

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

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

Add(delta int):給計(jì)數(shù)器增加delta,比如啟動(dòng)1個(gè)協(xié)程就增加1。

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

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

考一考

下面的程序是創(chuàng)建了協(xié)程father,然后father協(xié)程創(chuàng)建了10個(gè)子協(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ù),而此時(shí)Wait()函數(shù)可能已經(jīng)在執(zhí)行,甚至Wait()函數(shù)在所有Add()執(zhí)行前就執(zhí)行了,Wait()執(zhí)行時(shí)立馬就滿足了WaitGroup的計(jì)數(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í)行的時(shí)間是否早于Wait函數(shù)的執(zhí)行時(shí)間,但是,我們可以在分配協(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

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

相關(guān)文章

  • Go實(shí)現(xiàn)SMTP郵件發(fā)送訂閱功能(包含163郵箱、163企業(yè)郵箱、谷歌gmail郵箱)

    Go實(shí)現(xiàn)SMTP郵件發(fā)送訂閱功能(包含163郵箱、163企業(yè)郵箱、谷歌gmail郵箱)

    這篇文章給大家介紹了Go實(shí)現(xiàn)SMTP郵件發(fā)送訂閱功能(包含163郵箱、163企業(yè)郵箱、谷歌gmail郵箱),需求很簡(jiǎn)單,就是用戶輸入自己的郵箱后,使用官方郵箱給用戶發(fā)送替郵件模版,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下
    2023-10-10
  • golang包循環(huán)引用的幾種解決方案總結(jié)

    golang包循環(huán)引用的幾種解決方案總結(jié)

    golang有包循環(huán)引用問題,用過的應(yīng)該都知道,下面這篇文章主要給大家介紹了關(guān)于golang包循環(huán)引用的幾種解決方案,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-09-09
  • Go?iota關(guān)鍵字與枚舉類型實(shí)現(xiàn)原理

    Go?iota關(guān)鍵字與枚舉類型實(shí)現(xiàn)原理

    這篇文章主要介紹了Go?iota關(guān)鍵字與枚舉類型實(shí)現(xiàn)原理,iota是go語(yǔ)言的常量計(jì)數(shù)器,只能在常量的表達(dá)式中使用,更多相關(guān)內(nèi)容需要的小伙伴可以參考一下
    2022-07-07
  • golang如何使用gos7讀取S7200Smart數(shù)據(jù)

    golang如何使用gos7讀取S7200Smart數(shù)據(jù)

    文章介紹了如何使用Golang語(yǔ)言的Gos7工具庫(kù)讀取西門子S7200Smart系列PLC的數(shù)據(jù),通過指定數(shù)據(jù)塊號(hào)、起始字節(jié)偏移量和數(shù)據(jù)長(zhǎng)度,可以精確讀取所需的數(shù)據(jù),感興趣的朋友跟隨小編一起看看吧
    2024-12-12
  • golang優(yōu)先級(jí)隊(duì)列的實(shí)現(xiàn)全過程

    golang優(yōu)先級(jí)隊(duì)列的實(shí)現(xiàn)全過程

    優(yōu)先級(jí)隊(duì)列是一種特殊隊(duì)列,下面這篇文章主要給大家介紹了關(guān)于golang優(yōu)先級(jí)隊(duì)列的實(shí)現(xiàn)全過程,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-12-12
  • 深入理解Golang中指針的用途與技巧

    深入理解Golang中指針的用途與技巧

    在 Go 語(yǔ)言中,指針是一種重要的概念,了解和正確使用指非常關(guān)鍵,因此本文小編就來和大家講講Golang 中指針的概念與用法,希望對(duì)大家有所幫助
    2023-05-05
  • Golang排序和查找使用方法介紹

    Golang排序和查找使用方法介紹

    排序操作和查找一樣是很多程序經(jīng)常使用的操作。盡管一個(gè)最短的快排程序只要15行就可以搞定,但是一個(gè)健壯的實(shí)現(xiàn)需要更多的代碼,并且我們不希望每次我們需要的時(shí)候都重寫或者拷貝這些代碼
    2022-12-12
  • Go切片的具體使用

    Go切片的具體使用

    本文主要介紹了Go切片的具體使用,包括聲明切片、初始化切片、切片的切割、切片的添加、切片的刪除、切片的復(fù)制、切片的遍歷、多維切片等,感興趣的可以了解一下
    2023-11-11
  • 解決go 生成的exe不在bin文件夾里的問題

    解決go 生成的exe不在bin文件夾里的問題

    這篇文章主要介紹了解決go 生成的exe不在bin文件夾里的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Go代碼的組織和格式化規(guī)則實(shí)戰(zhàn)示例

    Go代碼的組織和格式化規(guī)則實(shí)戰(zhàn)示例

    這篇文章主要為大家介紹了Go代碼的組織和格式化示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08

最新評(píng)論

麻阳| 海门市| 独山县| 孙吴县| 阳泉市| 大洼县| 平阳县| 尼木县| 城固县| 任丘市| 彭泽县| 台北县| 沧州市| 保定市| 额济纳旗| 广平县| 南昌县| 渝中区| 景宁| 饶阳县| 苏尼特左旗| 庐江县| 资溪县| 成武县| 庆云县| 延津县| 静安区| 平遥县| 黄石市| 绥芬河市| 宜兰市| 苍溪县| 垣曲县| 沁阳市| 宾川县| 沅江市| 固阳县| 望谟县| 东乌| 永年县| 惠来县|