GO:同步工具WaitGroup
什么是 WaitGroup?
WaitGroup
是 Go 的标准库 sync
包中提供的一种并发控制工具,用于等待一组 goroutine 完成工作。它非常适合在主线程需要等待一组 goroutine 全部完成时使用。
通俗解释
可以把 WaitGroup
想象成一个计数器:
- 启动任务时:给计数器加 1。
- 任务完成时:给计数器减 1。
- 等待所有任务完成时:程序会阻塞,直到计数器变为 0。
用生活中的例子理解:
- 一个老师(主 goroutine)安排 3 个学生(goroutines)做作业。
- 每个学生做完后告诉老师。
- 老师会等所有学生都完成后才下班(主 goroutine 退出)。
基本用法
sync.WaitGroup
的主要方法:
Add(delta int)
:增加或减少计数器值。Done()
:减少计数器值(等价于Add(-1)
)。Wait()
:阻塞当前 goroutine,直到计数器变为 0。
示例代码:
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done() // 任务完成时调用 Done
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Second) // 模拟工作
fmt.Printf("Worker %d done\n", id)
}
func main() {
var wg sync.WaitGroup
// 启动 3 个 goroutine
for i := 1; i <= 3; i++ {
wg.Add(1) // 增加计数器
go worker(i, &wg)
}
wg.Wait() // 等待所有 goroutine 完成
fmt.Println("All workers done")
}
输出结果:
Worker 1 starting
Worker 2 starting
Worker 3 starting
Worker 1 done
Worker 2 done
Worker 3 done
All workers done
关键点解析
-
wg.Add(1)
:
每次启动一个 goroutine,计数器加 1。 -
defer wg.Done()
:
每个 goroutine 完成任务时,计数器减 1。 -
wg.Wait()
:
主 goroutine 阻塞,直到计数器变为 0,表示所有 goroutine 都完成了工作。
注意事项
-
必须匹配
Add
和Done
:
每个Add
对应一个Done
,否则程序会死锁。 -
调用顺序:
在调用Wait()
之前,Add
的操作必须完成;否则可能导致意外行为。 -
避免重复使用:
一个WaitGroup
实例只能用于一组任务,任务完成后不能重用。
总结
WaitGroup
是 Go 中用于管理并发任务的一种同步工具。- 通过计数器机制,可以确保主线程等待所有 goroutine 完成后再继续执行。
- 它是 Go 并发编程中常用的基础工具之一。