
本文讲解如何使用 sync.waitgroup 配合 channel 实现:在启动多个 goroutine 并发执行任务的同时,实时消费返回结果,并在所有任务完成后优雅关闭 channel,避免死锁。
本文讲解如何使用 sync.waitgroup 配合 channel 实现:在启动多个 goroutine 并发执行任务的同时,实时消费返回结果,并在所有任务完成后优雅关闭 channel,避免死锁。
在 Go 中,并发执行多个任务(如调用外部命令 os/exec)并逐个处理结果,是一个常见需求。但若直接对未关闭的无缓冲 channel 使用 for range 循环,程序将因无法判断“何时结束”而陷入死锁——正如错误提示 fatal error: all goroutines are asleep - deadlock! 所示。根本原因在于:range 会持续阻塞等待新值,而发送方(goroutine)结束后未显式关闭 channel,导致接收方永远等待。
解决方案的核心是分离“发送完成信号”与“结果接收逻辑”,借助 sync.WaitGroup 精确跟踪所有 goroutine 的生命周期,并在全部完成时关闭 channel。以下是推荐实现:
package main
import (
"fmt"
"sync"
)
func execTask(input int, results chan<p><strong>关键要点说明:</strong> </p>
-
sync.WaitGroup提供线程安全的计数器,Add()初始化总数,Done()在每个 goroutine 结束时调用,Wait()阻塞直到计数归零; -
close(results)必须由唯一确定所有发送者已退出的 goroutine 执行(此处为go func(){...}()),否则可能引发 panic; -
for range results会在 channel 关闭且缓冲区清空后自然退出,无需额外标志位或超时; - 实时性保障:结果一旦写入 channel,主循环立即处理,无需等待其他 goroutine 完成——这正是并发模型的优势;
- 若需限制并发数(避免资源耗尽),可在外层加
semaphore或使用带缓冲的 worker pool,而非简单go execTask(...)。
综上,WaitGroup + close(channel) 是 Go 中协调“多生产者、单消费者”场景的标准范式,兼顾安全性、简洁性与实时响应能力。










