在 Go 语言中,sync.WaitGroup
是一个用于等待一组 goroutine 完成的计数器。它通常用于协调多个 goroutine 的执行,以确保所有 goroutine 都完成了它们的任务之后再继续执行后续代码。
关于嵌套使用 sync.WaitGroup
,答案是可以的,但需要小心处理以避免常见的并发问题,如竞态条件和死锁。嵌套使用意味着在一个 WaitGroup
的等待范围内启动另一个 WaitGroup
,通常用于更复杂的并发控制场景。
下面是一个简单的示例,展示了如何嵌套使用 sync.WaitGroup
:
package main import ( "fmt" "sync" "time"
) func worker(id int, wg *sync.WaitGroup, parentWG *sync.WaitGroup) { defer wg.Done() fmt.Printf("Worker %d starting\n", id) time.Sleep(time.Second) // 模拟工作 fmt.Printf("Worker %d done\n", id) // 嵌套的 WaitGroup var nestedWG sync.WaitGroup for j := 0; j < 2; j++ { nestedWG.Add(1) go func(j int) { defer nestedWG.Done() fmt.Printf(" Nested worker %d.%d starting\n", id, j) time.Sleep(500 * time.Millisecond) // 模拟嵌套工作 fmt.Printf(" Nested worker %d.%d done\n", id, j) }(j) } // 等待所有嵌套 worker 完成 nestedWG.Wait() // 通知父 WaitGroup 当前 worker 完成 parentWG.Done()
} func main() { var wg sync.WaitGroup for i := 0; i < 3; i++ { wg.Add(1) go worker(i, &wg, &wg) // 这里将同一个 wg 传递给 worker 作为父和嵌套 wg,仅为示例 } // 等待所有 worker 完成 wg.Wait() fmt.Println("All workers done")
}
在这个例子中,每个 worker
goroutine 创建了两个嵌套的 goroutine,并使用一个嵌套的 WaitGroup
来等待这些嵌套 goroutine 完成。然后,每个 worker
在其完成后通知外部的 WaitGroup
。
需要注意的是:
- 避免竞态条件:确保对
WaitGroup
的Add
和Done
调用是正确匹配的,否则会导致Wait
永远阻塞。 - 正确处理嵌套层级:确保每个层级的
WaitGroup
都正确管理其对应的 goroutine。 - 代码可读性:嵌套使用
WaitGroup
可能会使代码变得复杂,因此建议在实际项目中谨慎使用,并确保代码具有良好的可读性和可维护性。
这个示例中的 worker
函数将同一个 WaitGroup
(wg
)作为参数传递,但通常在实际应用中,你可能需要为每个层级使用不同的 WaitGroup
实例,以避免混淆和错误。