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