0

0

Golang如何使用sync.WaitGroup_Go语言并发等待机制

P粉602998670

P粉602998670

发布时间:2026-01-20 14:53:44

|

102人浏览过

|

来源于php中文网

原创

WaitGroup 必须在 Add 前初始化且不可复制;Add 参数须为编译期确定的正整数,需在 goroutine 启动前调用;Wait 后不可再 Add;Wait 不响应 context 超时,应配合 channel 或使用 errgroup.Group。

golang如何使用sync.waitgroup_go语言并发等待机制

WaitGroup 必须在 Add 前初始化,且不能在 Add 后再复制

Go 中 sync.WaitGroup 是值类型,但内部包含指针字段(如 state1)。一旦调用 Add(),其内部状态被激活;若此时将 WaitGroup 变量赋值给另一个变量(即发生复制),新副本会丢失对原状态的引用,导致 Wait() 永远阻塞或 panic。

  • var wg sync.WaitGroup 是安全的初始化方式;new(sync.WaitGroup)&sync.WaitGroup{} 也合法,但没必要
  • 禁止写 wg2 := wg 后在 goroutine 中对 wg2 调用 Done() —— 这不会影响原始 wg
  • 常见错误:在循环中启动 goroutine 时,把 wg 作为参数传入闭包,却未传地址 —— 应传 &wg

Add 的数值必须在 Go 启动前确定,不能靠 runtime 判断

WaitGroup.Add() 的参数必须是已知正整数(或负数用于抵消),不能在 goroutine 内部动态计算后调用。因为 Add()Done() 需要严格配对,且 Add(0) 是合法的(但无实际作用),而 Add(-1) 在计数为 0 时会 panic。

  • 正确做法:遍历任务列表前,先 wg.Add(len(tasks))
  • 错误模式:go func() { wg.Add(1); defer wg.Done(); ... }() —— 这会导致竞争,Add 和 Done 不在同一线程上下文,且可能多次 Add 同一逻辑单元
  • 若任务数量动态生成(如 channel 消费),应改用 for range + 外层 Add,或换用 errgroup.Group

Wait 之后不能再调用 Add,否则 panic: sync: WaitGroup is reused before previous Wait has returned

WaitGroup 不是可重用对象。一旦调用 Wait() 并返回,该实例即进入“已等待”状态;若再次调用 Add(),运行时会直接 panic。这不是 bug,而是设计约束 —— 它强制你明确生命周期。

阳光订餐系统
阳光订餐系统

欢迎使用阳光订餐系统,本系统使用PHP5+MYSQL开发而成,距离上一个版本1.2.8发布已经有一年了。本系统集成了留言本,财务管理,菜单管理,员工管理,安全管理,WAP手机端等功能,并继续继承1.X老版本简单、实用、美观的特点,在老版本上的基础上做了如下更新:1.更简洁的前台与后台,菜单及功能布局更合理。2.更合理的文件结构,合理适度的模板机制以及OO运用,更易于理解的代码,更适于二次开发;3.

下载
  • 常见误用:在一个函数里反复 wg.Add(); go f(); wg.Wait(); wg.Add(); ...
  • 解决方法:每次需要等待新一批任务时,声明新的 var wg sync.WaitGroup
  • 如果确实需复用(如长周期 worker),应避免 Wait(),改用 sync.Cond 或 channel 通知机制

和 context.WithTimeout 组合时,Wait 不会自动响应取消

WaitGroup.Wait() 是无条件阻塞,它不感知 context.Context。即使你用 context.WithTimeout 控制整体超时,Wait() 仍会等到所有 Done() 调用完毕才返回 —— 这可能导致超时后仍在等待。

立即学习go语言免费学习笔记(深入)”;

  • 正确组合方式:用 select 包裹 Wait(),配合 done := make(chan struct{}) 手动通知
  • 更推荐方案:用 errgroup.Group(来自 golang.org/x/sync/errgroup),它原生支持 WithContext
  • 不要试图在 goroutine 中调用 Wait() 然后用 time.AfterFunc 关闭 —— 无法中断正在阻塞的 Wait
func waitWithTimeout(wg *sync.WaitGroup, timeout time.Duration) bool {
	done := make(chan struct{})
	go func() {
		wg.Wait()
		close(done)
	}()
	select {
	case <-done:
		return true
	case <-time.After(timeout):
		return false
	}
}
WaitGroup 的核心限制其实就一条:它只负责“计数同步”,不负责“生命周期管理”或“错误传播”。一旦你开始纠结“怎么让它支持取消”“怎么复用”“怎么传进闭包”,大概率说明该换抽象了 —— 比如 errgroupsemaphore 或自定义带状态的协调器。

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

179

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

228

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

340

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

209

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

392

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

197

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

191

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

192

2025.06.17

Java JVM 原理与性能调优实战
Java JVM 原理与性能调优实战

本专题系统讲解 Java 虚拟机(JVM)的核心工作原理与性能调优方法,包括 JVM 内存结构、对象创建与回收流程、垃圾回收器(Serial、CMS、G1、ZGC)对比分析、常见内存泄漏与性能瓶颈排查,以及 JVM 参数调优与监控工具(jstat、jmap、jvisualvm)的实战使用。通过真实案例,帮助学习者掌握 Java 应用在生产环境中的性能分析与优化能力。

3

2026.01.20

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 4万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号