• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    Golang中的sync包的WaitGroup操作

    sync的waitgroup功能

    WaitGroup

    使用多线程时,进行等待多线程执行完毕后,才可以结束函数,有两个选择

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

    但是,如果线程一旦增多,就会导致代码冗余,增加负担,可以使用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 {//创建一个结构体
     Num int//线程的个数
     ok chan bool//线程与函数通信的管道
    }
    func (t *Wait) Add (n int){//初始化线程个数
     t.Num = n
     t.ok = make(chan bool , n)
    }
    func (t *Wait) Done (){//执行完一个线程之后,执行的函数,每执行完一个线程,调用函数,使用通信管道进行传输一个true
     t.ok - true
    }
    func (t *Wait) Wait () {//等待函数,每次管道中放入一个true,说明,执行完一个线程,t.Num--,如果等于0说明所有线程执行结束
     for - t.ok {
      t.Num--
      if t.Num == 0 {
       break
      }
     }
    }

    补充:Golang的WaitGroup陷阱

    sync.WaitGroup是并发环境中,一个相当常用的数据结构,用来等待所有协程的结束,在写代码的时候都是按着例子的样子写的,也没用深究过它的使用。前几日想着能不能在协程中执行Add()函数,答案是不能,这里介绍下。

    陷阱在WaitGroup的3个函数的调用顺序上。先回顾下3个函数的功能:

    Add(delta int):给计数器增加delta,比如启动1个协程就增加1。

    Done():协程退出前执行,把计数器减1。

    Wait():阻塞等待计数器为0。

    考一考

    下面的程序是创建了协程father,然后father协程创建了10个子协程,main函数等待所有协程结束后退出,看看下面代码有没有什么问题?

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

    发现问题了吗?如果没有看下面的运行结果:main函数在子协程结束前就开始结束了。

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

    陷阱分析

    产生以上问题的原因在于,创建协程后在协程内才执行Add()函数,而此时Wait()函数可能已经在执行,甚至Wait()函数在所有Add()执行前就执行了,Wait()执行时立马就满足了WaitGroup的计数器为0,Wait结束,主程序退出,导致所有子协程还没完全退出,main函数就结束了。

    正确的做法

    Add函数一定要在Wait函数执行前执行,这在Add函数的文档中就提示了: Note that calls with a positive delta that occur when the counter is zero must happen before a Wait.。

    如何确保Add函数一定在Wait函数前执行呢?在协程情况下,我们不能预知协程中代码执行的时间是否早于Wait函数的执行时间,但是,我们可以在分配协程前就执行Add函数,然后再执行Wait函数,以此确保。

    下面是修改后的程序,以及输出结果。

    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

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。

    您可能感兴趣的文章:
    • 解决Golang 中使用WaitGroup的那点坑
    • 在golang中使用Sync.WaitGroup解决等待的问题
    • Golang中的sync.WaitGroup用法实例
    • Golang标准库syscall详解(什么是系统调用)
    • Golang的os标准库中常用函数的整理介绍
    • Golang 标准库 tips之waitgroup详解
    上一篇:go-kit组件使用hystrix中间件的操作
    下一篇:Golang模拟令牌桶进行对访问的限流方式
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    Golang中的sync包的WaitGroup操作 Golang,中的,sync,包的,WaitGroup,