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

目录
  • 一、前言
  • 二、waitgroup使用示例
  • 三、waitgroup使用注意事项
  • 四、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用法内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 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(

  • 在golang中使用Sync.WaitGroup解决等待的问题

    面对goroutine我们都需要等待它完成交给它的事情,等待它计算完成或是执行完毕,所以不得不在程序需要等待的地方使用time.Sleep()来睡眠一段时间,等待其他goroytine执行完毕,下面的代码打印1到100的for循环可以在很快的时间内运行完毕,但是我们必须添加time.Sleep()来等待其打印完毕,如果我们不等待仿佛什么也没有发生一样.....这肯定不是我们想要的! func main(){ for i := 0; i < 100 ; i++{ go fmt.Println(i)

  • Golang中的sync.WaitGroup用法实例

    WaitGroup的用途:它能够一直等到所有的goroutine执行完成,并且阻塞主线程的执行,直到所有的goroutine执行完成. 官方对它的说明如下: A WaitGroup waits for a collection of goroutines to finish. The main goroutine calls Add to set the number of goroutines to wait for. Then each of the goroutines runs and

  • Golang 标准库 tips之waitgroup详解

    WaitGroup 用于线程同步,很多场景下为了提高并发需要开多个协程执行,但是又需要等待多个协程的结果都返回的情况下才进行后续逻辑处理,这种情况下可以通过 WaitGroup 提供的方法阻塞主线程的执行,直到所有的 goroutine 执行完成. 本文目录结构: WaitGroup 不能被值拷贝 Add 需要在 Wait 之前调用 使用 channel 实现 WaitGroup 的功能 Add 和 Done 数量问题 WaitGroup 和 channel 控制并发数 WaitGroup 和

  • 解决Golang 中使用WaitGroup的那点坑

    sync.WaitGroup对于Golang开发者来说并不陌生,其经常作为多协程之间同步的一种机制.用好它势必会让你事半功倍,但是一旦错用将引发问题. 关于WaitGroup的使用网上有很多例子,在此就不做介绍了,我想说的是我在项目中使用WaitGroup遇到的坑. 在项目中,因为服务器有同步需求, 所以直接使用了WaitGroup,但是未考虑使用场景,结果在项目上线之后,高峰期的时候客户端经常出现卡顿,经过多方查找,才发现如果使用WaitGroup的时候,未启动单独的goroutine,那么极

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

    目录 一.前言 二.waitgroup使用示例 三.waitgroup使用注意事项 四.waitgroup使用总结 附:陷阱避免 总结 一.前言 waitgroup在golang中,用于线程同步,指等待一个组,等待一个系列执行完成后,才会向下执行,可以解决一个 进程goroutine 等待多个该进程启动的子线程goroutine 都正常运行完成的场景,这个比较常见的场景就是例如 后端 main processer 启动了多个消费者worker干活,还有爬虫并发爬取数据,多线程下载等等,为了保证主

  • Go基础教程系列之WaitGroup用法实例详解

    正常情况下,新激活的goroutine(协程)的结束过程是不可控制的,唯一可以保证终止goroutine(协程)的行为是main goroutine(协程)的终止.也就是说,我们并不知道哪个goroutine(协程)什么时候结束. 但很多情况下,我们正需要知道goroutine(协程)是否完成.这需要借助sync包的WaitGroup来实现. WatiGroup是sync包中的一个struct类型,用来收集需要等待执行完成的goroutine(协程).下面是它的定义: type WaitGrou

  • Go语言基础枚举的用法及示例详解

    目录 概述 一.普通枚举 二.自增枚举 注意 代码 概述 将变量的值一一列举出来,变量只限于列举出来的值的范围内取值 Go语言中没有枚举这种数据类型的,但是可以使用const配合iota模式来实现 一.普通枚举 const ( cpp = 0 java = 1 python = 2 golang = 3 ) 二.自增枚举 iota只能在常量的表达式中使用 fmt.Println(iota) //undefined: iota 它默认开始值是0,const中每增加一行加1 const ( a =

  • GoLang的sync.WaitGroup与sync.Once简单使用讲解

    目录 一.sync.WaitGroup的简单实用 Add方法 Done方法 Wait方法 二.sync.WaitGroup类型值中计数器的值可以小于0吗 三.sync.Once 用法 sync.Once类型中的uint32类型的字段 Do方法的功能特点 一.sync.WaitGroup的简单实用 在之前,我们使用通道,来主goroutine中等待其他goroutine执行完成: func coordinateWithChan() { sign := make(chan struct{}, 2)

  • JQuery中基础过滤选择器用法实例分析

    本文实例讲述了JQuery中基础过滤选择器用法.分享给大家供大家参考.具体如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <he

  • IOS Swift基础之switch用法详解

    IOS  Swift基础之switch用法详解 概述 Swift中的switch语句与Java等语言中的switch有很大的相似点,但是也有不同的地方,并且更加灵活. Swift中switch的case语句中不需要添加break Swift中需要考虑所有情况,default是必要的. case分支可以添加多个条件,用,分割 case不局限与常量,可以使使用范围 switch里可以使用元组 switch默认不需要添加break,执行一个case之后就跳出语句,如果想要继续下面的语句可以使用fall

  • golang简单tls协议用法完整示例

    本文实例讲述了golang简单tls协议用法.分享给大家供大家参考,具体如下: 生成私钥: openssl genrsa -out key.pem 2048 生成证书: openssl req -new -x509 -key key.pem -out cert.pem -days 3650 https: 复制代码 代码如下: package main import (     "io"     "net/http"     "log" ) fun

  • jquery-mobile基础属性与用法详解

    本文实例讲述了jquery-mobile基础属性与用法.分享给大家供大家参考,具体如下: 写在前面 本文是根据w3c 学习轨迹,自己研习过程中记录下的笔记,只供自己学习轨迹记录之用,不喜勿喷. 0. 引入库 引入对应的文件: <link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.2/jquery.mobile-1.3.2.min.css"> <script src="

  • Python装饰器基础概念与用法详解

    本文实例讲述了Python装饰器基础概念与用法.分享给大家供大家参考,具体如下: 装饰器基础 前面快速介绍了装饰器的语法,在这里,我们将深入装饰器内部工作机制,更详细更系统地介绍装饰器的内容,并学习自己编写新的装饰器的更多高级语法. 什么是装饰器 装饰是为函数和类指定管理代码的一种方式.Python装饰器以两种形式呈现: [1]函数装饰器在函数定义的时候进行名称重绑定,提供一个逻辑层来管理函数和方法或随后对它们的调用. [2]类装饰器在类定义的时候进行名称重绑定,提供一个逻辑层来管理类,或管理随

  • 详解Golang中Channel的用法

    如果说goroutine是Go语言程序的并发体的话,那么channels则是它们之间的通信机制.一个channel是一个通信机制,它可以让一个goroutine通过它给另一个goroutine发送值信息. 1 创建channel 每个channel都有一个特殊的类型,也就是channels可发送数据的类型.一个可以发送int类型数据 的channel一般写为chan int.使用内置的make函数,如果第二个参数大于0,则表示创建一个带缓存的channel. ch := make(chan in

随机推荐