Golang 等待组 sync.WaitGroup 的用法

马谦马谦马谦 Golang评论5,0953字数 1107阅读 3 分 41 秒阅读模式

一、 waitgroup 介绍

多线程编程中,经常会遇到这样的一种场景:main 函数中为了等待其他线程执行完,在 return 之前都要执行 sleep 以争取更多的时间给其他线程执行。例如:

主线程为了等待 goroutine 都运行完毕,不得不在程序的末尾使用 time.Sleep() 来睡眠一段时间,等待其他线程充分运行。对于简单的代码,100 个 for 循环可以在 1 秒之内运行完毕,time.Sleep() 也可以达到想要的效果。但是对于实际场景来说,大多无法预知 for 循环内代码运行时间的长短,因此 1 秒可能是不够的。所以睡眠也就达不到我们想要的效果。

那么我们可能又会想到使用管道来完成同步,因为管道本身就是用来作为数据通信使用的,用在此处也合理。于是就有了这样的代码:

首先可以肯定的是使用管道是能达到我们的目的的,但是问题是管道用在这里真的合适吗?管道是 go 中用来给多个线程 (协程) 间通信的,使用它来仅仅作为状态同步,是不是有点大材小用了。而且,管道是基于共享内存实现的,假设我们有一万、十万甚至更多的 for 循环,也要申请同样数量大小的管道出来,对系统性能也会造成更多的负载。

WaitGroup(等待组) 就是用来解决这种问题的,它主要用于同步多个协程间的状态 (例如等待所有协程都执行完) 。

WaitGroup 对象实现中,内部有一个计数器,最初从 0 开始,它有三个方法:

  • Add():计数器加一
  • Done():计数器减一
  • Wait():等待计数器清零

执行 Wait 方法的函数在等待组内部计数器不为 0 的时候回阻塞,一旦计数器为 0 了,程序就会继续往下执行。

利用 WaitGroup 实现上面的代码:

程序刚开始首先把 wg 计数设置为 100,然后开启 100 个协程执行任务,每个协程执行完成之后把计数器减 1,主线程中等待计数清零。当 wg.Wait()继续向下执行了,也就说明所有的协程都执行完了。

可以看出,相较于管道来说,WaitGroup 更简单,也更轻量。

二、注意事项

2.1 计数器不能为负值

使用等待组时注意不能通过 Add()wg 设置一个负值,否则代码将会报错:

同样使用 Done()也要特别注意不要把计数器设置成负数了。

2.2 WaitGroup 对象不是一个引用类型

WaitGroup 对象不是一个引用类型,在通过函数传值的时候需要使用地址:

  最后更新:2020-2-22
马谦马谦马谦
  • 本文由 马谦马谦马谦 发表于 2018 年 3 月 1 日 22:23:38
  • 转载请务必保留本文链接:https://www.dyxmq.cn/program/code/golang/waitgroup-in-golang.html
解决gvm工具无法下载安装包的问题 Golang

解决 gvm 工具无法下载安装包的问题

GVM(Go Version Manager) 是一款用于管理和切换不同 Go 语言版本的工具。它允许用户在同一台计算机上轻松安装、使用和管理多个 Go 版本,同时还能确保项目之间的依赖关系井然有序。 GVM 的主...
goland配置proto文件搜索路径 Golang

goland 配置 proto 文件搜索路径

默认情况下,goland(jetbrains 家的软件:idea 、 pycharm 、 phpstorm 以及 webstorm 都是一样) 安装 protobuf 插件后只会在一个特定的库路径下搜索 proto 文件。如果...
国内几个优质的Go Module代理仓库服务 Golang

国内几个优质的 Go Module 代理仓库服务

一、简介 go module 公共代理仓库,代理并缓存 go 模块。你可以利用该代理来避免 DNS 污染导致的模块拉取缓慢或失败的问题,加速你的构建。 简单来说就是国内访问被墙,go get 无法在线获取到仓库,...
Golang中glog库的使用方法 Golang

Golang 中 glog 库的使用方法

一、关于 glog 库 golang 中的 glog 库是 google 著名开源 C++日志库 glog 的 golang 版本,在 golang 默认日志库的基础上做了更进一层的封装使得该库能更贴近日常使用。项目首页为 gol...
匿名

发表评论

匿名网友
:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:
确定

拖动滑块以完成验证