在Go语言中,sync.WaitGroup 是一种用于等待一组 goroutine 完成的同步机制。正确使用 sync.WaitGroup 可以避免并发编程中的等待问题。以下是正确使用 sync.WaitGroup 的步骤和注意事项:
WaitGroup首先,你需要创建一个 sync.WaitGroup 实例。
var wg sync.WaitGroup
在启动每个 goroutine 之前,调用 Add 方法来增加 WaitGroup 的计数器。计数器表示需要等待的 goroutine 数量。
wg.Add(1) // 增加计数器
在启动 goroutine 时,将 WaitGroup 的指针传递给 goroutine,以便在 goroutine 完成时减少计数器。
go func() {
defer wg.Done() // 减少计数器
// 执行任务
}()
在主 goroutine 中,调用 Wait 方法来阻塞,直到所有 goroutine 完成(即计数器归零)。
wg.Wait() // 阻塞,直到计数器归零
以下是一个完整的示例,展示了如何正确使用 sync.WaitGroup:
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.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
for i := 1; i <= 5; i++ {
wg.Add(1) // 增加计数器
go worker(i, &wg)
}
wg.Wait() // 等待所有 goroutine 完成
fmt.Println("All workers done")
}
Add 和 Done 的调用次数匹配:每次调用 Add 增加计数器后,必须确保在相应的 goroutine 中调用 Done 来减少计数器。否则,Wait 会一直阻塞。Done:Done 应该在 goroutine 内部调用,以确保在任务完成后减少计数器。WaitGroup 的指针:在 goroutine 中传递 WaitGroup 时,应该传递指针,而不是值。因为 WaitGroup 是一个结构体,传递值会导致副本的创建,从而无法正确同步。Add:如果忘记调用 Add,Wait 会立即返回,因为计数器为零。Done:如果忘记调用 Done,Wait 会一直阻塞,因为计数器不会归零。Done:如果在 goroutine 外部调用 Done,可能会导致计数器减少过早,导致 Wait 提前返回。通过遵循上述步骤和注意事项,你可以正确使用 sync.WaitGroup 来避免并发编程中的等待问题。