首页 > 后端开发 > Golang > 正文

sync.WaitGroup在Golang中如何等待所有goroutine完成任务

P粉602998670
发布: 2025-08-30 09:46:01
原创
542人浏览过
sync.WaitGroup通过计数器协调goroutine完成。1. 初始化后,在启动goroutine前调用Add增加计数;2. 每个goroutine结束时调用Done减少计数,推荐使用defer wg.Done()确保执行;3. 主goroutine调用Wait阻塞,直到计数器归零。常见陷阱是Add调用时机错误,必须在go语句前执行,否则可能导致竞态条件或死锁。最佳实践包括:始终在启动goroutine前Add,使用defer wg.Done()保证通知,避免复制WaitGroup。

sync.waitgroup在golang中如何等待所有goroutine完成任务

sync.WaitGroup
登录后复制
在Golang中主要通过一个内部计数器来协调goroutine的完成。当需要等待一组goroutine时,我们会在启动它们之前调用
Add
登录后复制
方法增加计数,每个goroutine完成任务后调用
Done
登录后复制
方法递减计数。主goroutine则通过调用
Wait
登录后复制
方法阻塞,直到这个计数器归零,表示所有被追踪的goroutine都已完成。

当我们在Golang中处理并发任务时,经常会遇到一个场景:启动多个goroutine去执行一些工作,然后主goroutine需要等待所有这些子goroutine都完成,才能继续执行后续逻辑,或者安全地退出程序。

sync.WaitGroup
登录后复制
就是为此而生的。

它的核心机制其实很简单:

  1. 初始化:声明一个
    var wg sync.WaitGroup
    登录后复制
  2. 计数器增加:在启动任何需要等待的goroutine之前,调用
    wg.Add(delta int)
    登录后复制
    。这个
    delta
    登录后复制
    通常是你即将启动的goroutine数量。每调用一次
    Add(1)
    登录后复制
    ,内部计数器就加一。
  3. 任务完成通知:在每个goroutine内部,当其任务即将完成时,调用
    wg.Done()
    登录后复制
    。这会将内部计数器减一。一个非常好的实践是使用
    defer wg.Done()
    登录后复制
    ,这样即使goroutine内部发生panic,
    Done()
    登录后复制
    也能被执行,避免主goroutine永远等待。
  4. 等待:在主goroutine中,调用
    wg.Wait()
    登录后复制
    。这个方法会阻塞当前goroutine,直到
    WaitGroup
    登录后复制
    的内部计数器变为零。

来看个例子,这能让你更直观地理解:

立即学习go语言免费学习笔记(深入)”;

有道小P
有道小P

有道小P,新一代AI全科学习助手,在学习中遇到任何问题都可以问我。

有道小P 64
查看详情 有道小P
package main

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

func worker(id int, wg *sync.WaitGroup) {
    // 确保无论如何,这个goroutine完成时都会通知WaitGroup
    defer wg.Done() 
    fmt.Printf("Worker %d starting...\n", id)
    time.Sleep(time.Duration(id) * time.Second) // 模拟工作
    fmt.Printf("Worker %d finished.\n", id)
}

func main() {
    var wg sync.WaitGroup
    numWorkers := 3

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

    fmt.Println("Main: Waiting for all workers to complete...")
    wg.Wait() // 阻塞直到所有worker都调用了Done()

    fmt.Println("Main: All workers completed. Exiting.")
}
登录后复制

运行这段代码,你会看到主goroutine在启动所有

worker
登录后复制
之后,会一直等到所有
worker
登录后复制
都打印出"finished"才继续执行
"Main: All workers completed. Exiting."
登录后复制
。这正是我们想要的效果。

我个人在使用

WaitGroup
登录后复制
时,最常犯的一个小错误,或者说容易忽略的细节,就是
Add
登录后复制
的时机。它必须在对应的
go
登录后复制
语句之前调用。如果你在
go worker(i, &wg)
登录后复制
之后才
wg.Add(1)
登录后复制
,那么在某些极端情况下,如果
worker
登录后复制
执行得特别快,可能在
Add
登录后复制
被调用之前就已经
Done
登录后复制
了,这会导致计数器不匹配,
Wait
登录后复制
可能会提前返回或者永远等待。所以,顺序很重要。

Golang
sync.WaitGroup
登录后复制
有哪些常见的陷阱和最佳实践?

在使用

sync.WaitGroup
登录后复制
时,虽然它看起来直观,但

以上就是sync.WaitGroup在Golang中如何等待所有goroutine完成任务的详细内容,更多请关注php中文网其它相关文章!

相关标签:
最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号