Golang中的sync.WaitGroup详解:原理、用法与避坑指南

不晚
不晚
发布时间:2026-10-15 | 3人浏览过
原创

在Go语言并发编程中,等待一组goroutine全部执行完成是常见的需求。sync.WaitGroup提供了优雅且线程安全的解决方案。本文将解析其核心机制、正确用法及常见的并发陷阱。

sync.WaitGroup的核心功能与原理

sync.WaitGroup用于等待一组goroutine执行完成。当主协程需要等待所有子协程任务结束后再继续执行后续逻辑时,它是首选工具。它通过维护一个内部计数器来实现同步:

  • Add(delta int):修改内部计数器。delta参数通常为1(新增任务)或-1(任务结束),支持负数参数调整,但需极度谨慎以避免导致计数器变为负数从而引发Panic。
  • Done():标记某个goroutine已完成执行。它的本质等价于调用 Add(-1),减少计数器的值。
  • Wait():当前调用该方法的goroutine会在此处阻塞,直到内部计数器归零。即等待所有调用了 Add 的任务都成功执行了 Done。

值得注意的是,sync.WaitGroup是开箱即用且并发安全的(Concurrent-safe),适合在多协程环境下操作。

使用场景与操作步骤

假设我们需要并行处理N个任务,并在所有任务完成后输出汇总结果。操作流程如下:

第1步:实例化WaitGroup

在主函数或初始化阶段创建变量:

var wg sync.WaitGroup

第2步:启动任务前增加计数器

在每次调用 go 关键字新建一个协程之前,必须调用 wg.Add(1)。这告诉WaitGroup即将有一个新任务加入。

wg.Add(1)

第3步:编写业务逻辑并使用Done收尾

在子协程内部执行具体业务后,务必确保计数器减一。推荐使用 defer wg.Done() 将其放在函数第一行,以保证无论函数是否发生异常退出,计数器都能被正确回收。

func worker(id int) {
	defer wg.Done() // 推荐写法,确保资源释放
	// 模拟耗时操作
	time.Sleep(1 * time.Second)
	log.Printf("Worker %d finished\n", id)
}

第4步:主协程调用Wait等待

所有的 go 语句发放完毕后,主协程调用 wg.Wait()。此时程序将暂停执行后续代码,直到所有子协程都执行完 Done。

wg.Wait()
log.Println("All workers completed.")

完整实战代码

以下代码展示了如何同时启动5个goroutine处理数据,待它们全部完成后打印最终日志:

package main

import (
	"log"
	"sync"
	"time"
)

func main() {
	// 创建等待组
	var wg sync.WaitGroup

	// 循环创建5个并发任务
	for i := 1; i <= 5; i++ {
		// 每个任务开始前增加计数
		wg.Add(1)

		// 并发执行匿名函数,传入索引i
		go func(index int) {
			// 确保任务结束后自动将计数减一
			defer wg.Done()

			// 模拟业务逻辑执行耗时
			time.Sleep(1 * time.Second)
			log.Printf("第 %d 个goroutine执行完了", index)
		}(i)
	}

	// 阻塞主程序,直到所有goroutine调用过Done()
	wg.Wait()
	log.Println("所有goroutine都执行完了")
}

必须注意的并发陷阱

尽管API简单,但在实际工程中使用sync.WaitGroup时有几个关键的雷区:

1. 杜绝计数器变负导致的Panic

如果调用 Done() 的次数多于 Add() 的次数,导致计数器变成负数,运行时将触发 panic。因此,请严格保证 Add 和 Done 的数量对应关系,且通常建议在循环外部统一进行Add,或者采用闭包传递计数的方式管理。

2. Wait方法必须在最后调用

Wait() 具有阻塞特性。如果在发送任务(启动 go)之前就调用了Wait,主协程会直接卡死等待永远不会到来的0值信号,从而导致死锁(Deadlock)。

3. 正确管理Done的调用时机

正如上文所说,Done() 必须在 goroutine 彻底结束前执行。若因为业务逻辑提前返回(例如报错退出)而导致 Done() 未被执行,计数器将永远无法归零,导致 Wait() 永久挂起。因此,defer wg.Done() 是最稳健的做法。

以上就是Go语言中同步工具sync.WaitGroup的详细解析与使用指南,更多关于Go高并发编程的资料请关注本站其它相关文章!

相关标签:

本站声明

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

Python 相关产品和应用

全部下载

专题列表