在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
来避免并发编程中的等待问题。