在Go语言中,sync.WaitGroup
是一种用于等待一组 goroutine 完成的同步机制。正确使用 sync.WaitGroup
可以避免并发编程中的等待问题,确保主 goroutine 在所有子 goroutine 完成后再继续执行。以下是正确使用 sync.WaitGroup
的步骤和注意事项:
WaitGroup
首先,你需要创建一个 sync.WaitGroup
实例。
var wg sync.WaitGroup
在启动每个 goroutine 之前,调用 wg.Add(1)
来增加 WaitGroup
的计数器。这个计数器表示你期望等待的 goroutine 数量。
wg.Add(1)
在启动 goroutine 时,将 wg.Done()
放在 goroutine 的最后,以确保在 goroutine 完成时减少计数器。
go func() {
defer wg.Done() // 确保在 goroutine 结束时调用 Done
// 你的并发任务代码
}()
在主 goroutine 中调用 wg.Wait()
,这会阻塞主 goroutine,直到所有子 goroutine 完成(即计数器变为 0)。
wg.Wait()
以下是一个完整的示例,展示了如何正确使用 sync.WaitGroup
:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1) // 增加计数器
go func(i int) {
defer wg.Done() // 确保在 goroutine 结束时调用 Done
time.Sleep(time.Second * time.Duration(i))
fmt.Printf("Goroutine %d done\n", i)
}(i)
}
wg.Wait() // 等待所有 goroutine 完成
fmt.Println("All goroutines done")
}
确保 wg.Add
在 goroutine 启动之前调用:如果在 goroutine 启动之后再调用 wg.Add
,可能会导致主 goroutine 在子 goroutine 完成之前就调用了 wg.Wait()
,从而导致程序提前退出。
确保 wg.Done
被调用:在每个 goroutine 的最后调用 wg.Done()
,或者使用 defer wg.Done()
来确保即使 goroutine 发生 panic,wg.Done()
也会被调用。
避免计数器为负数:如果 wg.Done()
被调用的次数超过了 wg.Add()
的次数,WaitGroup
的计数器会变为负数,这会导致 panic。
通过正确使用 sync.WaitGroup
,你可以有效地管理并发任务,确保主 goroutine 在所有子 goroutine 完成后再继续执行。遵循上述步骤和注意事项,可以避免并发编程中的等待问题。