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 实现多协程间的同步等待。
  • • 使用时避免竞态和变量捕获问题。

相关推荐
Terio_my2 小时前
Spring Boot 缓存集成实践
spring boot·后端·缓存
karry_k3 小时前
JMM与Volatitle
后端
数字化顾问3 小时前
“AMQP协议深度解析:消息队列背后的通信魔法”之核心概念与SpringBoot落地实战
开发语言·后端·ruby
武子康4 小时前
大数据-115 - Flink DataStream Transformation Map、FlatMap、Filter 到 Window 的全面讲解
大数据·后端·flink
用户4099322502124 小时前
转账不翻车、并发不干扰,PostgreSQL的ACID特性到底有啥魔法?
后端·ai编程·trae
程序新视界4 小时前
三种常见的MySQL数据库设计最佳实践
数据库·后端·mysql
LunarCod5 小时前
Hexo搭建/部署个人博客教程
后端·hexo·个人博客·vercel
IT_陈寒6 小时前
Vue 3.4 实战:这7个Composition API技巧让我的开发效率飙升50%
前端·人工智能·后端
风雨同舟的代码笔记7 小时前
ThreadLocal的使用以及源码分析
后端
brzhang7 小时前
把网页的“好句子”都装进侧边栏:我做了个叫 Markbox 的收藏器,开源!
前端·后端·架构