Go 1.25 的 WaitGroup.Go 省了两行代码,也补不上这三个并发边界 Go 1.25 给sync.WaitGroup增加了Go方法。常见的 goroutine 启动代码可以从手工Add、go、defer Done缩成一次调用var wg sync.WaitGroup for _, job : range jobs { job : job wg.Go(func() { process(job) }) } wg.Wait()这个 API 首先修正的是启动顺序。过去有人把wg.Add(1)写进 goroutinego func() { wg.Add(1) defer wg.Done() process(job) }() wg.Wait()Wait可能在Add执行前看到计数为零提前返回。Go 1.25 的go vet新增 waitgroup 检查会报告这类误放的Add。WaitGroup.Go把计数增加与 goroutine 创建放进同一个标准方法降低了写错顺序的机会。它没有提供错误传播。f func()没有返回值业务函数失败后仍要自己决定如何记录、汇总或取消其他任务。若一组任务要求“任意一个失败就停止”errgroup.Group或自建带 context 的协调层仍更合适。不能为了使用新 API把错误吞进日志后继续执行。第二个边界是 panic。WaitGroup.Go的文档要求传入函数不能 panic。即使运行时能够执行计数清理业务也不能把 panic 当普通错误流。需要隔离不可信插件或任务时应在明确的边界恢复 panic附带堆栈并转成系统能够处理的失败状态而不是假定 WaitGroup 会替你定义语义。第三个边界是并发数量。下面代码会为每个 job 立即创建 goroutinefor _, job : range jobs { job : job wg.Go(func() { process(job) }) }任务有几十个时很自然输入可能达到几十万时goroutine 栈、参数、下游连接和队列都会形成压力。WaitGroup 负责“等它们结束”不负责限流。可以在外层使用带容量的 channel 作为信号量或创建固定数量 worker 从任务 channel 读取。limit : make(chan struct{}, 32) for _, job : range jobs { job : job limit - struct{}{} wg.Go(func() { defer func() { -limit }() process(job) }) } wg.Wait()这段代码仍要考虑取消。如果调用方 context 已结束向limit发送可能继续阻塞。生产代码可以用select同时等待令牌与ctx.Done()并让process接收同一个 context。并发控制、取消与等待是三件事API 简化了一件不会自动组合其余两件。嵌套调用也是新方法的一个实用点。只要 WaitGroup 非空正在执行的Go启动的函数可以继续调用同一 WaitGroup 的Go。但这并不意味着任意生命周期都安全。第一次Go必须发生在空 WaitGroup 的Wait之前一轮任务结束后复用 WaitGroup也要等上一轮Wait返回再启动下一轮。迁移不必全仓替换。先运行 Go 1.25 的go vet ./...修复错误的 Add 位置。对单纯启动且不需要返回错误的任务改用WaitGroup.Go能减少样板代码。已有errgroup、worker pool 或专门任务执行器的地方保留原结构更清楚。API 新不等于抽象层级更高。测试方面别只断言最终结果数量。加入取消、任务阻塞、输入为空、并发上限和内部启动子任务的用例。配合 race detector 检查共享数据而不是把 WaitGroup 当作互斥锁。它只协调任务完成不保护 map、slice 或计数器。我会采用这条迁移规则纯 fire-and-wait 任务用WaitGroup.Go需要错误与联动取消时用 errgroup需要资源上限时加显式并发控制共享状态另设同步。两行样板消失是好事但并发程序真正难的部分从来不是那两行。还有一个容易被代码审查漏掉的点循环变量捕获。较新的 Go 版本已经调整了常见 for 循环变量语义但项目的 go.mod 版本、旧代码写法和自定义变量仍要看清。显式写job : job虽然有时不再必要却能让读者马上知道闭包使用的是本轮任务。迁移时不要顺手删除所有这类赋值。基准测试也要区分 API 开销和业务吞吐。WaitGroup.Go的目标是减少错误与样板不是承诺比手工写法更快。若基准出现明显差异先检查任务粒度、逃逸和测试噪声。对大多数网络服务数据库与网络等待远大于这几行协调代码。最后检查可观测性。批量启动任务时给每轮操作一个 trace 或批次标识记录启动数、完成数、失败数和取消数。Wait 返回只能证明计数归零不能证明每个任务达成业务结果。把完成协调与结果统计分开事故时才能回答究竟丢在哪一步。

本月热点