如何在Golang中处理多任务同步_Golang sync包与WaitGroup应用技巧
技术百科
P粉602998670
发布时间:2026-01-20
浏览: 次 WaitGroup.Add()必须在启动goroutine前调用,且参数>0;不可在goroutine中调用Add();defer wg.Done()不能漏括号;必须传指针避免复制;不解决数据竞争,共享变量需额外同步。
WaitGroup 必须在启动 goroutine 前调用 Add()
常见错误是先开 goroutine,再在 g

WaitGroup.Add(1) —— 这会导致 Wait() 可能永远阻塞,或 panic:「negative WaitGroup counter」。因为 Add() 和 Done() 不是原子配对操作,必须由主线程提前声明任务数。
-
Add()必须在go语句之前调用,且参数 > 0 - 若任务数动态不确定(比如从 channel 收集),需先遍历一次计数,或改用
sync.Map+ 计数器 - 传入 0 给
Add(0)合法但无意义;传负数直接 panic
别在 goroutine 里 defer WaitGroup.Done() 而不加括号
写成 defer wg.Done(漏掉括号)是静默错误:函数未执行,Done() 被当值传递,最终计数器不减,Wait() 永远不返回。Go 编译器不会报错,运行时行为完全异常。
go func() {
defer wg.Done() // ✅ 正确:带括号,实际调用
// ... work
}()
go func() {
defer wg.Done // ❌ 错误:只是取函数地址,不调用
// ... work
}()
WaitGroup 不能被复制,跨 goroutine 传递必须用指针
sync.WaitGroup 包含 mutex 等非可复制字段,值拷贝会破坏内部状态。常见于:将 wg 作为参数传给函数却用了值传递、在循环中创建临时 wg 变量。
- 函数参数类型必须是
*sync.WaitGroup,不是sync.WaitGroup - 切片或 map 中存 wg 也必须存指针:
[]*sync.WaitGroup - 初始化后不要赋值给另一个变量(如
wg2 := wg),否则后续Done()作用于副本,主 wg 无变化
WaitGroup 不解决数据竞争,共享变量仍需额外同步
WaitGroup 只保证 goroutine 执行完毕的时机,不保护读写共享内存。例如多个 goroutine 向同一 slice 追加元素,即使用了 WaitGroup,仍可能 panic 或丢数据。
- 写共享变量前,考虑
sync.Mutex、sync.RWMutex或channels - 优先用 channel 传递结果,而非让 goroutine 直接修改外部变量
- 简单累加可用
sync/atomic(如atomic.AddInt64),比锁更轻量
WaitGroup 的真正难点不在语法,而在于它只回答「都做完了吗」,从不回答「做对了吗」——共享状态的正确性,得靠你亲手守住。
# ai
# 用了
# 多个
# 可在
# 而非
# go
# golang
# 循环
# 指针
# 报错
# 线程
# 不确定
# 切片
# map
# channel
# 遍历
# 都做
# 主线程
# 值传递
# 不加
# 不解决
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- php打包exe怎么传递参数_命令行参数接收方法【
- php转mp4怎么设置帧率_调整php生成mp4视
- LINUX怎么进行文本内容搜索_Linux gre
- 如何使用Golang构建基础消息队列模拟_Gola
- 如何在Golang中编写端到端测试_Golang
- Win11怎么连接投影仪_Win11多显示器投屏设
- Python音视频处理高级项目教程_FFmpegP
- c++如何使用std::bind绑定函数参数_c+
- Win11怎么查看激活状态_查询Windows 1
- Win11怎么更改电脑名称_Windows 11修
- 如何使用Golang包导出规则_控制函数和变量可见
- Win11输入法切换快捷键怎么改_Windows
- Windows服务无法启动错误1067是什么_进程
- 如何提升Golang程序I/O性能_Golang
- Windows 10自带杀毒软件在哪_Window
- 如何在Golang中处理数据库事务错误_回滚和日志
- Win11如何更改用户账户文件夹名称 Win11修
- php后缀怎么变mp4能播放_让php伪装mp4正
- Win11开始菜单打不开_修复Windows 11
- 如何在Golang中使用log包输出不同级别日志_
- Win11如何设置文件权限 Win11 NTFS文
- php订单日志怎么记录评价_php记录订单评价日志
- c++中的Tag Dispatching是什么_c
- 如何使用Golang捕获并记录协程panic_保证
- MAC如何隐藏文件夹及文件_MAC终端命令隐藏与第
- c++怎么用jemalloc c++替换默认内存分
- 如何用列表一次性对 DataFrame 的指定列应
- Win10怎么限制单程序CPU占用上限_Win10
- 小程序里php怎么变mp4_小程序调用php生成m
- Python 模块的 __name__ 属性如何由
- Python类装饰器使用_元编程解析【教程】
- Win10怎样清理C盘爱奇艺缓存_Win10清理爱
- Win11开机自检怎么关闭_跳过Win11开机磁盘
- Mac如何将HEIC图片格式转为JPG_Mac批量
- Win11怎么关闭贴靠布局_Win11禁用窗口最大
- Linux怎么设置磁盘配额_Linux系统Quot
- php怎么下载安装后设置默认字符集_utf8配置步
- Win11怎么关闭自动维护 Win11禁用系统自动
- 如何使用Golang反射将map转换为struct
- Win11如何更新显卡驱动 Win11检查和安装设
- php中::能访问全局变量吗_全局作用域与类作用域
- Win11怎么设置开机自动连接宽带_Windows
- 如何使用Golang实现容器健康检查_监控和自动重
- Python与MongoDB NoSQL开发实战_
- Win11怎么关闭VBS安全性_Windows11
- Windows 11无法安全删除U盘提示设备正在使
- PythonFastAPI项目实战教程_API接口
- 如何更改Windows资源管理器的默认启动位置?(
- MAC如何安装Git版本控制工具_MAC开发环境配
- Win11怎么设置快速访问主页_Windows11

QQ客服