在Go语言中,sync.WaitGroup 用于等待一组goroutine完成执行。WaitGroup 通过内部的计数器来跟踪正在执行的goroutine数量。Add 方法增加计数器,Done 方法减少计数器,而 Wait 方法会阻塞,直到计数器归零。
为了避免 Wait 方法提前结束,你需要确保以下几点:
Add 和 DoneAdd 方法:在启动每个goroutine之前调用 Add 方法,增加计数器。通常是在主goroutine中调用 Add。Done 方法:在每个goroutine完成时调用 Done 方法,减少计数器。通常是在goroutine的末尾使用 defer wg.Done() 来确保 Done 一定会被调用。Add 和 Done 的调用次数匹配Add 方法增加计数器时,必须确保有对应的 Done 方法调用。如果 Add 的调用次数多于 Done,Wait 方法将永远不会返回。Done 的调用次数多于 Add,可能会导致 WaitGroup 的计数器变为负数,从而引发 panic。AddAdd,因为这可能导致 Wait 方法在 Add 被调用之前就已经返回。Add 方法应该在主goroutine中调用,以确保计数器在goroutine启动之前就已经增加。defer 确保 Done 被调用defer wg.Done() 来确保 Done 方法在goroutine结束时一定会被调用,即使goroutine中发生了 panic。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
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中使用 defer wg.Done()。Add。通过遵循这些规则,你可以避免 Wait 方法提前结束,确保程序正确等待所有goroutine完成。