【golang】 WaitGroup使用注意事项

ops/2024/12/13 2:53:48/

注意1:使用指针

  1. 当把WaitGroup作为参数传递给函数时,如果传递的是变量本身(值传递),会发生复制。在 Go 语言中,这种复制可能会导致意外的行为。因为每个WaitGroup副本都有自己独立的计数器
  2. 下面的代码如果worker(wg)这里没有传递指针,那么worker函数接收到的是wg的一个副本。worker函数中的Done操作是在副本上进行的,而main函数中的Wait操作是在原始的wg上进行的。这样就会导致main函数中的Wait可能永远阻塞,因为原始wg的计数器没有被正确地减少。
   package mainimport ("fmt""sync")func worker(wg *sync.WaitGroup) {defer wg.Done()fmt.Println("Worker is running")}func main() {var wg sync.WaitGroupwg.Add(1)// 传递指针worker(&wg)wg.Wait()}

注意2:正确的计数器操作顺序

这一点十分容易出现很隐蔽的错误

  1. Add方法调用时机:必须在goroutine 启动之前调用Add方法来增加计数器的值。如果在goroutine已经启动之后再调用Add,可能会导致Wait方法提前返回,因为计数器没有正确反映正在运行的goroutine的数量。把握住:Add()与Wait()保证在同一个函数中

           var wg sync.WaitGroup// 错误示例,在goroutine启动后才调用Addgo func() {wg.Add(1)fmt.Println("Goroutine is running")wg.Done()}()wg.Wait()
    

    下面是一个更加隐蔽的例子:

    func TestDistribute(t *testing.T) {numOfTask := 5resChan := make(chan int, numOfTask)addTaskChan := make(chan *AddTask, numOfTask)var wg sync.WaitGroupgo initTask(addTaskChan, numOfTask, 11, resChan)go DistributeTasks(addTaskChan, numOfTask, &wg)  // 没有在开启协程之前Add,开启之后在内部Add,就容易出问题res := 0wg.Wait()-----------------------------------
    func DistributeTasks(taskChan <-chan *AddTask, numOfTasks int, wg *sync.WaitGroup) {for task := range taskChan {wg.Add(1) // 在下面这个协程Add,只能保证在这个位置进行wg.Wait(),外面的函数无法保证go func(t *AddTask) {defer wg.Done()t.Do()}(task) // 注意要当作参数传入,而不是直接在 开启的协程 内部调用task,// wg.Wait() 在这个地方有效,外部就不行了}
    }
    

注意3:var wg sync.WaitGroup与wg := sync.WaitGroup{}区别

  1. var wg sync.WaitGroup
    这种写法声明了一个 sync.WaitGroup 类型的变量 wg,但是它没有进行初始化,默认情况下是零值初始化。Go 中的零值初始化意味着 wg 会被自动初始化为 sync.WaitGroup{},即一个空的 WaitGroup,你可以直接使用它。
  2. wg := sync.WaitGroup{}
    这种写法是对 sync.WaitGroup 的显式初始化,并且是局部变量的声明方式。 var wg sync.WaitGroup 的效果,初始化了一个新的空的 WaitGroup 变量。
  3. 使用 new(sync.WaitGroup) ,注意这里返回的是一个指针,这个时候回到第一点,传递wg的时候可以不需要使用 &wg取地址操作

http://www.ppmy.cn/ops/141111.html

相关文章

Advanced Functional Materials 光驱动连续跳跃机器人

跳跃是自然界生物的一种非常有效的运动手段&#xff0c;可以在瞬间穿越中长距离&#xff0c;以实现捕猎及逃避被猎捕的目的。自然界生物跳跃的机理主要有两种&#xff0c;长腿动物(比如袋鼠和青蛙)主要依靠杠杆作用&#xff0c;使它们能够用较少的力量跳跃同样的距离&#xff1…

MATLAB 非重叠点云提取算法(92)

MATLAB 非重叠点云提取算法(92) 一、算法介绍二、算法实现1.代码2.结果一、算法介绍 读取两片点云,从一片点云中找到与另一片点云不重叠的点云。输出并可视化提取过程和结果 二、算法实现 1.代码 代码如下(示例): % 假设 cloud1 和 cloud2 是通过 pcread 加载的点云…

分析比对vuex和store模式

在 Vue 中&#xff0c;Vuex 和 store 模式 是两个不同的概念&#xff0c;它们紧密相关&#xff0c;主要用于管理应用的状态。下面我会详细介绍这两个概念&#xff0c;并通过例子帮助你更好地理解。 1. Vuex 是什么&#xff1f; Vuex 是 Vue.js 的一个状态管理库&#xff0c;用…

Exp 智能协同管理系统-部门管理前端页面开发

一、需求分析 页面功能 提供部门信息的展示功能&#xff0c;数据以表格形式呈现&#xff0c;包含序号、部门名称、最后操作时间、操作&#xff08;编辑和删除&#xff09;列。用户可通过新增、编辑和删除功能&#xff0c;实现对部门数据的管理。数据动态加载&#xff0c;支持实…

使用Allure作为测试报告生成器(Java+Selenium)

背景 JAVA项目中原先用Jenkinsseleniumselenium grid来日常测试UI并记录。 问题 当某一个testSuite失败时&#xff0c;当需要确认UI regression issue还是selenium test case自身的问题&#xff0c;需要去jenkins中查log&#xff0c;一般得到的是“Can not find element xxx…

编程语言对决:Node.js与Python在视频处理领域

在当今的技术世界&#xff0c;视频处理是一个日益增长的需求&#xff0c;无论是在网络应用、数据分析还是桌面应用中。Node.js和Python都是流行的编程语言&#xff0c;它们各自拥有处理视频文件的能力&#xff0c;但它们在编程模型、内存管理和性能方面有所不同。本文将探讨这两…

【OpenCV】模板匹配

理论 模板匹配是一种在较大图像中搜索和查找模板图像位置的方法。为此&#xff0c;OpenCV 带有一个函数 cv.matchTemplate&#xff08;&#xff09; 。它只是在输入图像上滑动模板图像&#xff08;如在 2D 卷积中&#xff09;&#xff0c;并比较模板图像下的模板和输入图像的补…

关于SpringBoot项目创建后构建总是失败的问题

第一个问题&#xff1a;IDEA创建项目总是失败 原因&#xff1a;创建项目的时候默认使用的是https://start.spring.io&#xff0c;这个是一个外国网站&#xff0c;众所周知的就是国内访问总是出现不稳定的现象&#xff0c;这就是导致项目创建失败的最终原因。 解决方法&#x…