sync.WaitGroup
是 Go 语言标准库 sync
包提供的一个并发原语,用于等待一组 goroutine 完成任务。它通常用于主 goroutine 阻塞等待其他多个子 goroutine 执行完毕的场景。
核心方法
Add(delta int)
- 设置需要等待的 goroutine 数量(计数器增加
delta
)。 - 必须在启动 goroutine 前调用(通常在主协程中调用)。
- 设置需要等待的 goroutine 数量(计数器增加
Done()
- 表示一个 goroutine 完成(计数器减 1)。
- 在每个子 goroutine 退出前调用(通常用
defer
确保执行)。
Wait()
- 阻塞当前 goroutine,直到计数器归零。
- 一般在主协程中调用。
使用示例
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done() // goroutine结束时通知WaitGroup
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Second) // 模拟耗时任务
fmt.Printf("Worker %d done\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1) // 每启动一个goroutine,计数器加1
go worker(i, &wg)
}
wg.Wait() // 阻塞直到所有goroutine完成
fmt.Println("All workers completed")
}
关键注意事项
指针传递
WaitGroup必须通过指针传递给goroutine(值传递会导致副本失效)。Add与Done的平衡
如果Add
的累计值不等于实际调用的Done
次数,会导致死锁或 panic。不可复用
一个 WaitGroup在调用Wait()
后不能重复使用(需重新创建)。错误处理
如果某个goroutine可能出错退出,需确保Done()
被调用(例如结合defer+recover
)。
适用场景
- 批量异步任务的同步等待。
- 替代简单的
channel+select
同步逻辑。 - (注意:复杂依赖关系建议用更高级的并发模型如
errgroup
)
如果需要更复杂的控制(如超时、错误传递),可以结合 context.Context
或第三方库(如errgroup)。
内容由零声教学AI助手提供,问题来源于学员提问