Go并发系列:2基本同步原语-2.4 WaitGroup

121 阅读2分钟

2.4 WaitGroup

在并发编程中,我们经常需要等待一组 goroutine 完成后再继续执行下一步操作。Go 语言提供了 sync.WaitGroup 来实现这种需求,它允许我们通过计数器机制来等待一组 goroutine 完成执行。下面我们详细介绍 WaitGroup 的概念、使用方法及示例。

2.4.1 什么是WaitGroup

WaitGroup 是 Go 标准库 sync 包中的一种同步原语,用于等待一组 goroutine 完成执行。WaitGroup 通过一个计数器来跟踪 goroutine 的执行状态,当所有 goroutine 完成时,WaitGroup 允许程序继续执行。

WaitGroup 主要有三个方法:

  • Add:增加计数器的值,参数为正数。
  • Done:减少计数器的值,相当于 Add(-1)
  • Wait:阻塞,直到计数器的值变为零。

2.4.2 WaitGroup的使用方法

使用 WaitGroup 非常简单。首先,创建一个 WaitGroup 实例。在需要等待的每个 goroutine 启动前调用 Add 方法增加计数器的值,在每个 goroutine 完成时调用 Done 方法减少计数器的值,最后在主 goroutine 中调用 Wait 方法等待所有 goroutine 完成。以下是基本使用示例:

package main

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

func worker(id int, wg *sync.WaitGroup) {
    defer wg.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 <= 5; i++ {
        wg.Add(1)
        go worker(i, &wg)
    }

    wg.Wait()
    fmt.Println("All workers completed")
}

在这个例子中,我们启动了五个 goroutine,每个 goroutine 都在完成后调用 wg.Done()。主 goroutine 使用 wg.Wait() 等待所有 goroutine 完成。

2.4.3 WaitGroup的应用场景

WaitGroup 适用于以下场景:

  1. 并行任务等待:等待一组并行执行的任务完成后再继续执行后续操作。
  2. 批处理任务:在批处理任务中,启动多个 goroutine 并行处理任务,等待所有任务完成后汇总结果。
  3. 测试用例:在并发测试用例中,使用 WaitGroup 等待所有测试 goroutine 完成后检查测试结果。

2.4.4 示例代码

以下是一个使用 WaitGroup 实现并行计算平方值的示例:

package main

import (
    "fmt"
    "sync"
)

func calculateSquare(wg *sync.WaitGroup, num int, results chan<- int) {
    defer wg.Done()
    
    square := num * num
    results <- square
}

func main() {
    var wg sync.WaitGroup
    numbers := []int{2, 4, 6, 8, 10}
    results := make(chan int, len(numbers))

    for _, num := range numbers {
        wg.Add(1)
        go calculateSquare(&wg, num, results)
    }

    wg.Wait()
    close(results)

    for result := range results {
        fmt.Println("Square:", result)
    }
}

在这个示例中,我们启动多个 goroutine 并行计算平方值,并使用 WaitGroup 等待所有计算完成后,收集并打印结果。

结论

WaitGroup 是 Go 语言中用于等待一组 goroutine 完成的强大工具,通过简单的计数器机制,可以有效地协调多个 goroutine 的执行。在实际应用中,合理使用 WaitGroup 可以简化并发程序的设计,提高代码的可读性和维护性。在接下来的章节中,我们将继续探讨其他同步原语和并发编程技巧,帮助您更好地掌握 Go 的并发编程。