sync.WaitGroup的概念和使用方法

`sync.WaitGroup` 是 Go 语言中用于等待一组 goroutine 完成的结构。它通过计数器来跟踪正在执行的 goroutine 数量,并在计数器归零时解除阻塞。

### 概念

– **计数器**:`WaitGroup` 内部维护一个计数器,表示待完成的 goroutine 数量。
– **Add(delta int)**:增加或减少计数器的值,`delta` 为正数时增加,为负数时减少。
– **Done()**:将计数器减 1,通常在每个 goroutine 完成时调用。
– **Wait()**:阻塞当前 goroutine,直到计数器归零。

### 使用方法

1. **创建 `WaitGroup`**:声明一个 `sync.WaitGroup` 变量。
2. **增加计数器**:使用 `Add` 方法设置需要等待的 goroutine 数量。
3. **启动 goroutine**:在 goroutine 中执行任务,并在任务完成后调用 `Done`。
4. **等待完成**:在主 goroutine 中调用 `Wait`,等待所有 goroutine 完成。

### 示例代码

package main

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

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done() // 确保 goroutine 完成时调用 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 <= 3; i++ {
        wg.Add(1) // 每启动一个 goroutine,计数器加 1
        go worker(i, &wg)
    }

    wg.Wait() // 等待所有 goroutine 完成
    fmt.Println("All workers done")
}

### 输出

“`
Worker 1 starting
Worker 2 starting
Worker 3 starting
Worker 1 done
Worker 2 done
Worker 3 done
All workers done
“`

### 关键点

– **`Add` 调用时机**:应在启动 goroutine 前调用 `Add`,确保计数器正确。
– **`Done` 调用**:每个 goroutine 结束时必须调用 `Done`,通常使用 `defer` 确保执行。
– **`Wait` 调用**:主 goroutine 调用 `Wait` 以等待所有任务完成。

通过这些步骤,`sync.WaitGroup` 能有效管理多个 goroutine 的同步。