Go语言使用WaitGroup等待多个协程完成

 更新时间:2026年02月25日 11:00:19   作者:程序员爱钓鱼  
sync.WaitGroup是Go标准库中的一个结构体,用于等待一组goroutine执行完成,本文就来介绍一下Go语言使用WaitGroup等待多个协程完成,感兴趣的可以了解一下

在并发编程中,经常需要在主协程中等待多个子协程执行完毕再进行下一步操作。Go 提供了一个非常实用的同步原语:sync.WaitGroup,可以帮助我们优雅地解决这个问题。

一、什么是 WaitGroup?

sync.WaitGroup 是 Go 标准库中的一个结构体,用于等待一组 goroutine 执行完成。

常用方法:

方法功能说明
Add(n int)设置需要等待的 goroutine 数量
Done()每个 goroutine 执行完成后调用,计数器减 1
Wait()阻塞当前 goroutine,直到计数器归零为止

二、为什么需要 WaitGroup?

在并发场景中,如果主函数先于子协程执行完毕,程序将会直接退出,导致协程未完成任务。例如:

func main() {
    go func() {
        fmt.Println("Hello from goroutine")
    }()
    // 没有等待,主函数直接退出
}

输出往往为空或者输出不完整,根本原因是主 goroutine 没有等待子 goroutine。

三、实战案例:等待多个协程完成任务

示例:开启 5 个 goroutine,每个打印一条消息,主程序等待所有协程完成后再退出。

package main

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

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done() // 执行完毕,通知 WaitGroup
    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) // 启动一个 goroutine 前调用 Add(1)
        go worker(i, &wg)
    }

    wg.Wait() // 阻塞直到所有 Done() 被调用
    fmt.Println("所有任务已完成")
}

输出示例

Worker 1 starting
Worker 2 starting
Worker 3 starting
Worker 4 starting
Worker 5 starting
Worker 2 done
Worker 4 done
Worker 1 done
Worker 3 done
Worker 5 done
所有任务已完成

输出顺序可能每次不同,因为 goroutine 是并发执行的。

四、使用建议与注意事项

✅ 正确使用方式:

  • Add(n) 必须在 启动 goroutine 之前 调用。
  • 每个 goroutine 结束时必须调用 Done()。
  • Wait() 通常放在主 goroutine 中,阻塞直到所有任务完成。

⚠️ 易犯错误:

  1. 1. 忘记 Done()

    go func() {
        fmt.Println("hello")
        // 忘记 wg.Done(),会导致 wg.Wait() 永久阻塞
    }()
    
  2. 2. 在 goroutine 内调用 Add()

    go func() {
        wg.Add(1) // ❌不推荐:会出现数据竞争
        ...
    }()
    

    正确方式是主 goroutine 中统一 Add()。

五、封装使用:任务调度器

我们可以封装一个并发调度器,更加灵活:

type TaskScheduler struct {
    wg sync.WaitGroup
}

func (t *TaskScheduler) Run(task func()) {
    t.wg.Add(1)
    go func() {
        defer t.wg.Done()
        task()
    }()
}

func (t *TaskScheduler) Wait() {
    t.wg.Wait()
}

使用示例:

func main() {
    scheduler := TaskScheduler{}

    for i := 0; i < 5; i++ {
        index := i
        scheduler.Run(func() {
            fmt.Printf("Task %d running\n", index)
            time.Sleep(500 * time.Millisecond)
        })
    }

    scheduler.Wait()
    fmt.Println("All scheduled tasks completed.")
}

六、与其他同步机制对比

同步机制用途
sync.WaitGroup等待一组协程结束
sync.Mutex保护共享资源
sync.Once只执行一次的操作(如初始化)
channel通信为主,也可用于同步控制

七、结语

在并发控制中,sync.WaitGroup 是一种简单却非常强大的工具,能帮助我们控制 goroutine 的生命周期,避免程序提前退出或资源泄漏等问题。掌握其使用方法,是每位 Go 开发者的必备技能。

✅ 实战建议:在进行网络抓取、任务分发、并发计算等场景时,推荐优先考虑 WaitGroup 来管理协程。

到此这篇关于Go语言使用WaitGroup等待多个协程完成的文章就介绍到这了,更多相关Go WaitGroup等待多协程完成内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

相关文章

  • Golang 零值、空值与空结构的使用小结

    Golang 零值、空值与空结构的使用小结

    本文主要介绍了Golang 零值、空值与空结构的使用小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2026-02-02
  • vscode搭建go开发环境案例详解

    vscode搭建go开发环境案例详解

    对于Visual Studio Code开发工具,有一款优秀的GoLang插件,今天通过本文给大家介绍下vscode搭建go开发环境的详细教程,感兴趣的朋友跟随小编一起看看吧
    2021-12-12
  • 使用Go http重试请求的示例

    使用Go http重试请求的示例

    开发中对于http请求是经常遇到,一般可能网络延迟或接口返回超时,这篇文章主要介绍了使用Go http重试请求的示例,需要的朋友可以参考下
    2022-08-08
  • Go代码检查的推荐工具及使用详解

    Go代码检查的推荐工具及使用详解

    这篇文章主要为大家介绍了Go代码检查的推荐工具及使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • gin框架中使用JWT的定义需求及解析

    gin框架中使用JWT的定义需求及解析

    这篇文章主要为介绍了gin框架中使用JWT的定义需求及解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-04-04
  • Go map排序的实现示例

    Go map排序的实现示例

    map默认是无序的,不管是按照key还是按照value默认都不排序,本文主要介绍了Go map排序的实现示例,具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12
  • go使用errors.Wrapf()代替log.Error()方法示例

    go使用errors.Wrapf()代替log.Error()方法示例

    这篇文章主要为大家介绍了go使用errors.Wrapf()代替log.Error()的方法示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • 详解以go思想去处理js异常抛弃trycatch

    详解以go思想去处理js异常抛弃trycatch

    这篇文章主要为大家介绍了详解以go思想去处理js异常抛弃trycatch,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • Go并发读写文件、分片写、分片下载文件的实现示例

    Go并发读写文件、分片写、分片下载文件的实现示例

    读写文件在很多项目中都可以用到,本文主要介绍了Go并发读写文件、分片写、分片下载文件的实现示例,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • Go语言常用的打log方式详解

    Go语言常用的打log方式详解

    Golang的log包短小精悍,可以非常轻松的实现日志打印转存功能,下面这篇文章主要给大家介绍了关于Go语言常用的打log方式的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-10-10

最新评论