Go WaitGroup

3 min

Go等待组(WaitGroup)

1. 什么是等待组

  • WaitGroup 是 Go 语言标准库 sync 包提供的一个结构体,用于等待一组 goroutine 完成执行。
  • 它允许主 goroutine 等待多个其他 goroutine 完成它们的任务,然后再继续执行。

2. 为什么需要等待组

在并发编程中,经常需要在主 goroutine 等待所有子 goroutine 完成任务后再继续进行下一步操作。如果没有等待组,就需要自己管理计数器和锁,来确保所有子 goroutine 完成。这不仅容易出错,而且复杂。WaitGroup 提供了一个简洁的方法来解决这个问题。

  • 使用场景
  • 同步多个 goroutine:在需要同步等待多个并发任务完成时,使用 WaitGroup

  • 并行处理:例如,下载多个文件或处理多个请求时,主 goroutine 可以等待所有下载或处理完成后再继续执行。

3. 如何使用等待组

使用 WaitGroup 主要涉及三个方法:

  • Add(delta int):添加等待计数器的值。
    • 传入参数是增加等待组的值,Add(3)就是增加3个
  • Done():减少等待计数器的值,表示某个 goroutine 已经完成。
  • Wait():阻塞直到等待计数器变为零。

4. 示例代码

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

    const numWorkers = 5

    for i := 1; i <= numWorkers; i++ {
        wg.Add(1) // 每启动一个 goroutine,计数器加 1
        go worker(i, &wg)
    }

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

4.1 注意事项

  • 计数匹配:确保 AddDone 的调用数量匹配。每次 Add(1) 必须有相应的 Done() 调用。
  • 引用传递:将 *sync.WaitGroup 的指针传递给 goroutine,而不是值传递。
  • 不要嵌套 WaitGroup:一个 WaitGroup 不应被多个父 goroutine 同时等待。

5. 总结

WaitGroup 是 Go 语言中一个强大而简单的并发工具,用于协调多个 goroutine 的执行。它的使用能够有效简化并发编程中的同步问题,使代码更清晰和易于维护。在涉及并发任务时,WaitGroup 是一个非常有用的工具。