Go语言同步原语与数据竞争:WaitGroup

在Go语言并发编程中,我们经常需要等待多个 goroutine 执行完毕后再继续下一步操作。Go 提供的 sync.WaitGroup 就是专为这种**"等待一组任务完成"**而设计的同步原语。


一、基本原理

sync.WaitGroup 提供三个主要方法:

方法 说明
Add(n int) 设置等待的 goroutine 数量(加计数)
Done() 每个 goroutine 完成时调用(减计数)
Wait() 阻塞主 goroutine,直到计数归零

它内部使用计数器+条件变量,当所有 goroutine 都调用 Done() 后,Wait() 才会解除阻塞。


二、典型用法

示例:等待 10 个 goroutine 执行完毕

go 复制代码
package main

import (
    "fmt"
    "sync"
)

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done() // 每个 goroutine 完成时调用
    fmt.Printf("Worker %d is working...\n", id)
    // 模拟工作
}

func main() {
    var wg sync.WaitGroup

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

    wg.Wait() // 阻塞直到所有 goroutine 完成
    fmt.Println("All workers done.")
}

输出示意:

erlang 复制代码
Worker 1 is working...
Worker 2 is working...
...
All workers done.

三、常见错误及注意事项

1. Add() 必须在 goroutine 启动前调用

错误示例:

scss 复制代码
go func() {
    wg.Add(1) // 此时 goroutine 可能已开始执行,竞态风险
    ...
}()

正确做法:

scss 复制代码
wg.Add(1)
go func() {
    ...
    wg.Done()
}()

2. 不可重复使用已完成的 WaitGroup(没有"重置"功能)

WaitGroup 设计为一次性同步器,不建议重复使用,若确需控制并发次数,可用 sync.Poolsemaphore 替代。


四、结合匿名函数使用

go 复制代码
for i := 0; i < 5; i++ {
    wg.Add(1)
    go func(i int) {
        defer wg.Done()
        fmt.Println("i:", i)
    }(i)
}
wg.Wait()

⚠️ 注意:传参 i 必须显式传入闭包,避免捕获变量陷阱。


五、使用场景

  • • 等待一组任务执行完成(如:并发下载、批量计算)
  • • 控制主函数在 goroutine 完成后再退出
  • • 可搭配 Channel 和 Context 使用,实现更复杂的并发控制模型

六、小结

  • sync.WaitGroup 是 Go 并发编程中最常用的同步工具之一。
  • • 使用 Add/Done/Wait 实现多协程间的同步等待。
  • • 使用时避免竞态和变量捕获问题。

相关推荐
tedcloud1235 分钟前
OpenLogi 怎么搭建?用 Rust 打造一个轻量的 Logitech 外设管理工具
linux·运维·服务器·开发语言·后端·rust·开源
学长毕业设计39 分钟前
基于SpringBoot的健康食谱管理系统的设计与实现(源码+文档+讲解视频)
java·spring boot·后端
逃逸线LOF1 小时前
Spring的AOP简介
java·后端·spring
yume_sibai2 小时前
02-Rust 所有权与借用深入解析(底层原理 + 借用检查器 + 生命周期 + 内部可变性)
开发语言·后端·rust
卷无止境2 小时前
从脚本到程序:Windows平台上的Python打包全景图
后端·python
骇客野人2 小时前
Springboot 的 配置文件 application.yml 和 bootrap.yml 的由来和作用
java·spring boot·后端
岁月宁静2 小时前
三、《从零手撸 Agent》 · system prompt 与核心参数:调好你的旋钮
后端·python·agent
bcbnb2 小时前
Flutter-Notebook代码混淆:Android与iOS平台安全配置
后端·ios
泡海椒3 小时前
SpringBoot 集成 JQuick-Curl:Spring 环境完整接入教程,第三方接口调用别再到处手写模板类
后端
落木萧萧8253 小时前
MyBatis 关联查询的四种写法,为什么最后都变回了手写 XML
java·数据库·后端