在Go语言里,并发主要通过goroutine实现,但主函数往往在子任务还没跑完时就退出了。sync包中的WaitGroup可以帮我们阻塞主线程,等所有并发任务结束再继续。它适合用于一批独立任务需要全部完成后再做后续处理的场景。

sync WaitGroup是什么
WaitGroup是sync包下的一个结构体,内部维护一个计数器。我们可以通过下面三个方法来操作它:
Add(n int):给计数器增加n,通常在启动goroutine前调用Done():将计数器减1,一般在goroutine末尾调用Wait():阻塞当前goroutine,直到计数器变为0
基本使用示例
下面代码演示如何用WaitGroup等待五个并发任务完成:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
// 启动5个goroutine
for i := 1; i <= 5; i++ {
wg.Add(1) // 每启动一个任务计数器加1
go func(id int) {
defer wg.Done() // 任务结束计数器减1
time.Sleep(time.Second)
fmt.Println("任务", id, "完成")
}(i)
}
wg.Wait() // 阻塞直到所有任务调用Done
fmt.Println("全部任务结束")
}
使用时的注意点
计数器不能为负
如果Done()调用次数多于Add()指定的数量,程序会触发panic。因此要确保Add和Done的配对正确。
传值问题
WaitGroup不能当作值拷贝传递,否则计数器不共享。应传递指针或使用变量地址:
func worker(wg *sync.WaitGroup) {
defer wg.Done()
// 业务逻辑
}
func main() {
var wg sync.WaitGroup
wg.Add(1)
go worker(&wg)
wg.Wait()
}
复用限制
WaitGroup在计数器归零后可以被再次使用,但必须保证上一次的Wait调用已全部返回,不可在Wait期间并发调用Add。
常见错误写法
| 错误写法 | 原因 |
|---|---|
| 在goroutine内部调用wg.Add(1) | 可能导致Wait先返回,Add未生效 |
| 拷贝WaitGroup值传给函数 | 计数器不共享,Wait无法感知任务 |
总结
使用sync WaitGroup控制并发非常简单,核心就是Add、Done、Wait三步配合。只要注意计数器配对和指针传递,就能写出稳定可靠的并发等待逻辑。
Golangsync_WaitGroup并发控制修改时间:2026-07-31 09:12:18