当 Goroutine 需要等待:Go 中 sync.WaitGroup 的优雅使用

简介: 当 Goroutine 需要等待:Go 中 sync.WaitGroup 的优雅使用

当 Goroutine 需要等待:Go 中 sync.WaitGroup 的优雅使用

在 Go 并发编程中,我们经常遇到一个经典场景:启动多个 goroutine 执行任务,主程序需要等待所有任务完成后再继续。这时,sync.WaitGroup 就成为了我们的得力助手。

核心原理

WaitGroup 本质上是一个计数器。通过 Add() 增加计数,Done() 减少计数,Wait() 阻塞直到计数归零。这种简洁的 API 设计让并发等待变得异常清晰。

典型使用模式

var wg sync.WaitGroup

for _, task := range tasks {
   
    wg.Add(1)
    go func(t Task) {
   
        defer wg.Done()
        process(t)
    }(task)
}

wg.Wait()
fmt.Println("所有任务完成")

实用场景

  • 并行处理批量数据(如图片处理、文件上传)
  • 微服务中并发调用多个下游接口
  • 测试用例中的并发验证
  • 服务启动时的初始化协程

关键注意事项

  1. Add 要在 goroutine 外调用:避免竞态条件
  2. 使用 defer wg.Done():确保即使 panic 也能递减计数
  3. 不要复制 WaitGroup:传递时使用指针
  4. 计数归零后 WaitGroup 可复用:通过 Add 重新设置计数

进阶技巧

结合 context 实现带超时的等待:

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

done := make(chan struct{
   })
go func() {
   
    wg.Wait()
    close(done)
}()

select {
   
case <-done:
    // 正常完成
case <-ctx.Done():
    // 超时处理
}

WaitGroup 体现了 Go 的设计哲学:用简单的抽象解决复杂问题。掌握它,你就能优雅地驾驭并发等待场景,写出更健壮的 Go 程序。

记住:在并发世界中,有时等待比执行更需要智慧。

相关文章
|
21天前
|
Go 调度 开发者
实战Go并发模型:轻量级协程的高效应用
实战Go并发模型:轻量级协程的高效应用
223 145
|
21天前
|
安全 Go API
轻量并发实战:用Go的goroutine与channel优化任务处理
轻量并发实战:用Go的goroutine与channel优化任务处理
214 139
|
21天前
|
Cloud Native Go 开发者
为什么 Go 成为云原生时代的首选语言?
为什么 Go 成为云原生时代的首选语言?
202 138
|
4天前
|
Java 应用服务中间件 Shell
Apache Tomcat 历史版本下载地址 官网地址
本指南详解Tomcat (以7.0.67为例)的完整部署流程:从官网下载历史版本、解压安装,到启动/停止服务(startup.sh/shutdown.sh),再到配置开机自启(systemctl)。涵盖目录结构说明及端口验证方法,适合Linux服务器快速部署。
177 134
|
28天前
|
SQL 安全 网络安全
从黑客视角看SQL注入:你的数据真的安全吗?
从黑客视角看SQL注入:你的数据真的安全吗?
230 138
|
28天前
|
SQL 安全 数据库
SQL注入:从登录框到数据泄露的十分钟
SQL注入:从登录框到数据泄露的十分钟
216 140
|
21天前
|
存储 Go 数据库
掌控并发:Go Context 的实战精要
掌控并发:Go Context 的实战精要
219 139
|
21天前
|
安全 Go API
Go并发实战:用goroutine和channel实现高效网络请求
Go并发实战:用goroutine和channel实现高效网络请求
222 140
|
21天前
|
存储 Cloud Native Go
Go Context:高效并发控制的核心利器
Go Context:高效并发控制的核心利器
216 138
|
21天前
|
Go 开发者 微服务
Go错误处理:从`if err != nil`到清晰代码
Go错误处理:从`if err != nil`到清晰代码
229 137