Go语言中使用sync.WaitGroup等待后台Goroutine执行完成

Leo
Leo
发布时间:2026-10-14 | 3人浏览过
原创

在Go语言并发编程中,经常需要主流程等待若干个后台执行的Goroutine任务完成后,再进行后续处理或退出程序。本文介绍如何使用标准库中的sync.WaitGroup结构体来实现这一需求,确保资源释放和状态汇总的准确性。

结果与目标

使用sync.WaitGroup可以实现多个异步任务(Goroutine)的同步等待。当所有注册的计数器归零时,主线程或当前函数将解除阻塞,继续执行后续逻辑或正常结束程序。

准备条件

  1. 环境准备:已安装Go 1.x版本并配置好开发环境。
  2. 依赖引入:无需额外第三方库,直接使用Go标准库中的"sync"包。
  3. 逻辑设计:明确需要等待的任务数量,以便初始化计数器。

第1步:声明变量并设置计数器

首先需要创建sync.WaitGroup类型的变量,并使用Add()方法设置初始计数值。该值通常等于即将启动的Goroutine数量。

var wg sync.WaitGroup
wg.Add(2) // 设置需要等待的任务数量为2

重要参数:count为整数,代表后续调用Done()的次数。如果未正确设置,可能导致死锁或panic。

第2步:启动后台Goroutine并标记完成

启动Goroutine执行具体任务。在任务执行的最后(或在defer语句中),必须调用Done()方法,这会使计数器减1。

// 启动第一个协程
go func() {
    defer wg.Done() // 确保无论是否发生错误,计数器都会减1
    // do something
    fmt.Println("Task 1 completed")
}()

// 启动第二个协程
go func() {
    defer wg.Done()
    // do something
    fmt.Println("Task 2 completed")
}()

建议:推荐使用defer wg.Done()写法,这样可以防止因Goroutine内部提前返回或报错导致Done()未被调用,从而引发死锁。

第3步:主流程阻塞等待

在所有Goroutine启动后,主流程调用Wait()方法。该方法会阻塞直到计数器变为0。

wg.Wait()
fmt.Println("All tasks finished. Exiting.")

可观察状态:控制台输出前两个任务的日志后,才会打印最终的退出提示,证明主线程已成功等待所有子任务完成。

完整实例分析

以下是完整的代码结构,涵盖了从声明到等待的全过程:

package main

import (
	"fmt"
	"sync"
)

func main() {
	// 1. 初始化 WaitGroup
	var wg sync.WaitGroup
	wg.Add(2) // 预期执行2个任务

	// 2. 启动后台任务
	go func() {
		defer wg.Done()
		fmt.Println("Running Task 1...")
		// 模拟工作
	}()

	go func() {
		defer wg.Done()
		fmt.Println("Running Task 2...")
		// 模拟工作
	}()

	// 3. 等待所有任务完成
	wg.Wait()
	fmt.Println("All goroutines have exited.")
}

常见排错与维护

  • 死锁现象:如果Wait()被调用但某些Goroutine未调用Done(),程序将永久挂起。请检查是否有路径遗漏了Done()调用。
  • Panic异常:如果Add()的计数器小于0,或者在Wait()之后再次调用Add()且计数器不为0,可能会触发panic。请确保生命周期管理严格遵循顺序。

简要总结

掌握sync.WaitGroup的使用是编写健壮Go并发程序的基础。通过合理设置初始计数和使用defer保障完成标记,可以有效避免竞态条件和资源泄漏。以上就是Go语言使用sync.WaitGroup等待Goroutine完成的详细内容,更多关于Go并发编程的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表