• golang基础 :waitgroup用法及使用要点


    一、前言

    waitgroup在golang中,用于线程同步,指等待一个组,等待一个系列执行完成后,才会向下执行,可以解决一个 进程goroutine 等待多个该进程启动的子线程goroutine 同时结束的场景,这个比较常见的场景就是例如 后端 main processer 启动了多个消费者worker干活,还有爬虫并发爬取数据,多线程下载等等,为了保证主进程在所有的子线程完成后再退出,这时就要用上waitgroup

    二、使用示例

    我们这里模拟一个 worker 的例子

    package main
    
    import (
        "fmt"
        "sync"
        "time"
    )
    func worker(index int, w chan struct{}, wg *sync.WaitGroup) {
    	 defer wg.Done()
            time.Sleep(1 * time.Second)
            fmt.Println(time.Now())
            fmt.Println(index)
            <-w
    }
    func main() {
        wg := new(sync.WaitGroup)
        ws := make(chan struct{}, 3)
        for i := 0; i < 1000; i++ {
            ws <- struct{}{}
            wg.Add(1)
            go worker(i, ws, wg)
        }
        wg.Wait()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在这段代码中,main最后一行是

    wg.Wait()
    
    • 1

    这行代码保证有所的100个子线程全部都执行完成后才会退出main函数,如果没有最后一行wg.Wait(),可能会出现遍历完程序就直接结整了,有可能只有不确定个几个子线程执行完成,其它线程由于主线程main退出就直接退出了

    从这个例子我们也可以看到 waitgroup通常配合来限制并发线程个数和确保所有的线程都最终都执行完成
    这段代码中 ws 有三个缓冲,所以并发的数量是3,超过3个就要等待执行完成释放所占用通道后才能再开新的线程

    上面的代码,会在执行到wg.Wait()后等待,直到所有的1000线程全部执行完后才会继续往下执行

    可以説这段代码非常精妙

    三、使用注意事项

    同时我们在使用waitgroup时也要注意一些坑:

    1、 Add一个负数

    如果计数器的值小于0会直接panic

    2、 Add在Wait之后调用

    比如一些子协程开头调用Add结束调用Wait,这些 Wait无法阻塞子协程。正确做法是在开启子协程之前先Add特定的值。

    3、 未置为0就重用

    WaitGroup可以完成一次编排任务,计数值降为0后可以继续被其他任务所用,但是不要在还没使用完的时候就用于其他任务,这样由于带着计数值,很可能出问题。

    4、 复制waitgroup

    WaitGroup有nocopy字段,不能被复制。也意味着WaitGroup不能作为函数的参数

    WaitGroup是Golang应用开发过程中经常使用的并发控制技术,学习golang是我们必须要掌握和理解的机制之一,建议有时间了大家再进一步的研究一下WaitGroup的底层实现逻辑。

    如有问题,欢迎大家留言沟通,点赞支持!!!

  • 相关阅读:
    【黑马头条】-day11热点文章实时计算-kafka-kafkaStream-Redis
    golang关于数量的总结
    web测试与app测试的区别
    声音克隆,精致细腻,人工智能AI打造国师“一镜到底”鬼畜视频,基于PaddleSpeech(Python3.10)
    028-GUI事件处理,ActionListener事件,MouseListener事件
    怎样用Python识别条形码?
    java注解反射之自定义Retrofit 项目实战
    【C++11】右值引用和移动语义 {左值引用和右值引用;移动语义;解决函数传值返回的深拷贝问题;完美转发}
    linux解压文件命令
    咖啡技术培训:6款创意咖啡拿铁教程
  • 原文地址:https://blog.csdn.net/itopit/article/details/125525681