golang基础之waitgroup用法以及使用要点

 更新时间:2023年01月07日 14:21:19   作者:北漂燕郊杨哥  
WaitGroup是Golang并发的两种方式之一,一个是Channel,另一个是WaitGroup,下面这篇文章主要给大家介绍了关于golang基础之waitgroup用法以及使用要点的相关资料,需要的朋友可以参考下

一、前言

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

二、waitgroup使用示例

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

package main

import (
    "fmt"
    "sync"
    "time"
)
func worker(idx int, out chan struct{}, wg *sync.WaitGroup) {
	 defer wg.Done()
        time.Sleep(1 * time.Second)
        fmt.Println(time.Now())
        fmt.Println(idx )
        <-out 
}
func main() {
    wg := new(sync.WaitGroup)
    in := make(chan struct{}, 20)
    for i := 0; i < 200; i++ {
        in <- struct{}{}
        wg.Add(1)
        go worker(i, in, wg)
    }
    wg.Wait()
}

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

wg.Wait()

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

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

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

可以説这段代码非常精妙,示例代码执行结果如下:

同时我们也可以测试一下把最后一行

//wg.Wait()

注释掉,我们看一下程序会怎么执行

注释后,我们看到程序完成时,只有171个线程完成运行,剩下的20几个线程异常结束了,看不到任何返回结果

三、waitgroup使用注意事项

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

1、 Add一个负数

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

2、 Add在Wait之后调用

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

3、 未置为0就重用

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

4、 复制waitgroup

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

四、waitgroup使用总结

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

附:陷阱避免

1)WaitGroup 同步的是 goroutine, 如果在 goroutine 中进行 Add(1) 操作,可能在这些 goroutine 还没来得及 Add(1) 已经执行 Wait 操作,造成程序退出。

2)WaitGroup 传递给goroutine的时候,应该采用引用方式,从而避免发生副本拷贝而死锁。

总结

到此这篇关于golang基础之waitgroup用法以及使用要点的文章就介绍到这了,更多相关golang waitgroup用法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go语言遍历map实现(访问map中的每一个键值对)

    Go语言遍历map实现(访问map中的每一个键值对)

    这篇文章主要介绍了Go语言遍历map实现(访问map中的每一个键值对),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • GO语言基本数据类型总结

    GO语言基本数据类型总结

    这篇文章主要介绍了GO语言基本数据类型,较为详细的总结了GO语言的基本数据类型,对于GO语言的学习有一定的借鉴参考价值,需要的朋友可以参考下
    2014-12-12
  • 浅谈Go语言多态的实现与interface使用

    浅谈Go语言多态的实现与interface使用

    如果大家系统的学过C++、Java等语言以及面向对象的话,相信应该对多态不会陌生。多态是面向对象范畴当中经常使用并且非常好用的一个功能,它主要是用在强类型语言当中,像是Python这样的弱类型语言,变量的类型可以随意变化,也没有任何限制,其实区别不是很大
    2021-06-06
  • Go语言中日志的规范使用建议分享

    Go语言中日志的规范使用建议分享

    在任何服务端的语言项目中,日志是至关重要的组成部分,本文为大家整理了一些如何规范使用GO语言日志的建议,以及相应的实际示例,希望对大家有事帮助
    2024-01-01
  • Golang二维数组的使用方式

    Golang二维数组的使用方式

    之前给大家讲过很多二维数组的知识,今天重点给大家介绍Golang二维数组的使用方式,通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2021-05-05
  • golang 自旋锁的实现

    golang 自旋锁的实现

    这篇文章主要介绍了golang 自旋锁的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-11-11
  • Go语言包管理模式示例分析

    Go语言包管理模式示例分析

    这篇文章主要为大家介绍了Go语言包管理模式示例分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • Golang如何读取单行超长的文本详解

    Golang如何读取单行超长的文本详解

    这篇文章主要给大家介绍了关于Golang如何读取单行超长文本的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2021-12-12
  • 基于Go语言搭建静态文件服务器的详细教程

    基于Go语言搭建静态文件服务器的详细教程

    Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易,本文给大家介绍了基于Go语言搭建静态文件服务器的详细教程,文中通过图文和代码讲解的非常详细,需要的朋友可以参考下
    2024-10-10
  • Go语言基础模板设计模式示例详解

    Go语言基础模板设计模式示例详解

    这篇文章主要为大家介绍了Go语言基础设计模式之模板模式的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2021-11-11

最新评论