golang: sync.WaitGroup

88 阅读1分钟

在 Go 语言中,var wg sync.WaitGroup 表示声明一个 sync.WaitGroup 类型的变量 wg,它用于等待一组 goroutine 完成执行。这是 Go 并发编程中常用的同步机制。

核心作用

sync.WaitGroup 通过计数器管理 goroutine 的等待:

  • Add(n):增加计数器值 n(通常在启动 goroutine 前调用)
  • Done():减少计数器值 1(在 goroutine 结束时调用)
  • Wait():阻塞当前线程,直到计数器归零

使用步骤

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    var wg sync.WaitGroup

    for i := 1; i <= 3; i++ {
        wg.Add(1) // 每个任务开始前增加计数器
        go worker(i, &wg)
    }

    wg.Wait() // 阻塞直到所有任务完成
    fmt.Println("所有任务完成")
}

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done() // 确保任务结束时减少计数器

    fmt.Printf("Worker %d 开始工作\n", id)
    time.Sleep(time.Second * time.Duration(id)) // 模拟耗时操作
    fmt.Printf("Worker %d 完成\n", id)
}

关键注意事项

  1. 指针传递:必须传递 WaitGroup 的指针(&wg),否则会复制副本导致死锁
  2. Add 的位置:建议在启动 goroutine 前调用 Add,避免竞态条件
  3. defer Done():使用 defer 确保即使发生 panic 也会执行
  4. 计数器匹配:Add 的总增量必须与 Done 的调用次数严格相等

典型应用场景

  • 批量并发任务需要等待全部完成
  • 并行计算后汇总结果
  • 服务启动时需要等待多个初始化协程

错误示例分析

// 错误:未传递指针,导致死锁
var wg sync.WaitGroup
go func() {
    wg.Done()
}()
wg.Wait()

// 正确:传递指针
var wg sync.WaitGroup
wg.Add(1)
go func(w *sync.WaitGroup) {
    defer w.Done()
}(&wg)
wg.Wait()

通过合理使用 sync.WaitGroup,可以优雅地管理 Go 程序的并发流程。