在 Go语言 中,goroutine 是实现并发的核心机制。它轻量、高效,可以轻松启动成千上万个并发任务。然而,当我们启动多个 goroutine 后,如何确保主程序等待它们全部执行完毕再退出呢?这就需要用到 sync.WaitGroup —— 一个用于goroutine并发控制的标准同步原语。

sync.WaitGroup 是 Go 标准库 sync 包中的一个结构体,用于等待一组 goroutine 完成。它内部维护一个计数器,通过以下三个方法操作:
Add(delta int):增加或减少计数器的值(通常在启动 goroutine 前调用)Done():将计数器减 1(通常在 goroutine 结束时调用)Wait():阻塞当前 goroutine,直到计数器变为 0下面是一个简单的例子,展示如何使用 sync.WaitGroup 等待两个 goroutine 执行完毕:
package mainimport ( "fmt" "sync" "time")func worker(id int, wg *sync.WaitGroup) { defer wg.Done() // goroutine 结束时自动调用 Done() fmt.Printf("Worker %d 开始工作\n", id) time.Sleep(2 * time.Second) // 模拟耗时任务 fmt.Printf("Worker %d 工作完成\n", id)}func main() { var wg sync.WaitGroup // 启动 2 个 goroutine for i := 1; i <= 2; i++ { wg.Add(1) // 每启动一个 goroutine,计数器 +1 go worker(i, &wg) } wg.Wait() // 主 goroutine 在这里等待,直到计数器归零 fmt.Println("所有任务已完成!")}运行这段代码,你会看到类似如下输出:
Worker 1 开始工作Worker 2 开始工作Worker 1 工作完成Worker 2 工作完成所有任务已完成!WaitGroup 的状态需要在多个 goroutine 间共享,所以应传递 *sync.WaitGroup 指针。i),可能会出现竞态条件。建议将变量作为参数传入函数。Add(1),而不是在 goroutine 内部调用,以避免竞态。Wait() 返回,不要再次使用同一个 WaitGroup,除非重新初始化。下面是一个常见的错误写法:
// 错误!Add() 在 goroutine 内部调用,可能导致主 goroutine 先执行 Wait() 而计数器仍为 0for i := 1; i <= 2; i++ { go func() { wg.Add(1) defer wg.Done() // ... 工作 }()}wg.Wait()这种写法存在竞态条件:主 goroutine 可能在子 goroutine 调用 Add(1) 之前就执行了 Wait(),导致程序提前退出。
sync.WaitGroup 是 Go并发编程 中最常用的同步工具之一,特别适合用于“启动一批任务,然后等待它们全部完成”的场景。掌握它,是学习 Go语言 并发模型的重要一步。
记住三个关键词:Add、Done、Wait,配合使用即可优雅地管理多个 goroutine 的生命周期。
希望这篇教程能帮助你理解 sync.WaitGroup 的基本用法和最佳实践。如果你刚开始学习 goroutine并发控制,不妨动手运行上面的代码,加深理解!
本文由主机测评网于2025-12-10发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://www.vpshk.cn/2025125597.html