waitgroup 与 channel 协同实现可靠并发:waitgroup 确保任务完成等待,channel 传递结果与信号;单用任一机制均存在缺陷,协同可兼顾可靠性、灵活性与健壮性。

WaitGroup 和 Channel 协同工作,核心在于“职责分离”:WaitGroup 负责计数与等待完成,Channel 负责传递结果、信号或错误。两者不互斥,而是互补——用 WaitGroup 保底确保不漏等,用 Channel 实现灵活通信。
为什么不能只用其中一个?
单靠 WaitGroup 只能知道“做完了”,但拿不到返回值、无法响应超时、也不支持取消;单靠 Channel(尤其无缓冲)虽能同步,但若协程 panic 或未发送信号,主 goroutine 可能永久阻塞,且难以精确统计完成数量。协同使用可兼顾可靠性与表达力。
典型协同模式:WaitGroup 控制生命周期,Channel 收集产出
常见做法是:
- 主 goroutine 创建带缓冲的 Channel(容量 ≥ 预期结果数),避免发送阻塞
- 每个 worker 启动前调用
wg.Add(1),完成后调用defer wg.Done() - worker 执行完毕后,将结果或状态写入 Channel(注意检查
ctx.Done()避免向已关闭 channel 发送) - 另起一个 goroutine 调用
wg.Wait()后close(ch),保证 Channel 有序关闭 - 主 goroutine 用
for range ch安全接收所有结果
加入 Context 实现健壮控制
真实场景中需应对超时与取消,这时引入 context.Context:
- 用
context.WithTimeout或context.WithCancel构造上下文,传入每个 worker - worker 内部在耗时操作前后均 select 监听
ctx.Done(),及时退出 - Channel 接收侧也可配合
select加超时,防止range卡死(如 worker 少发了结果) - WaitGroup 仍负责兜底:哪怕部分 worker 因 cancel 提前退出,wg.Wait() 仍能准确反映“启动的任务是否都结束了”
关键细节提醒
几个容易出错但影响严重的点:
-
wg.Add()必须在 goroutine 启动前调用,否则存在竞态风险 - Channel 关闭必须由单一 goroutine 执行(通常是 wg.Wait() 后的那个),多次 close 会 panic
- 向已关闭的 channel 发送数据会 panic,接收则得到零值和 false;务必在发送前确认 channel 仍开放,或用 defer+recover(不推荐)
- 若需区分成功/失败结果,建议用结构体封装
{Value int, Err error}发送,而非混合类型 channel
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











