
本文讲解如何使用 sync.waitgroup 配合 channel 实现:在并发启动多个 goroutine(如执行外部命令)后,不阻塞地实时消费返回结果,并在全部任务结束后安全退出程序,避免死锁。
本文讲解如何使用 sync.waitgroup 配合 channel 实现:在并发启动多个 goroutine(如执行外部命令)后,不阻塞地实时消费返回结果,并在全部任务结束后安全退出程序,避免死锁。
在 Go 并发编程中,一个常见误区是:向无缓冲 channel 发送数据后,未显式关闭 channel 就直接用 for range 循环接收——这会导致主 goroutine 永久阻塞,引发 fatal error: all goroutines are asleep - deadlock!。根本原因在于:range 会持续等待新值,直到 channel 被关闭;而若无人调用 close(),且所有写入 goroutine 已退出,程序便陷入死锁。
正确的解法是分离“任务协调”与“结果消费”逻辑:用 sync.WaitGroup 跟踪所有 goroutine 的完成状态,并在最后统一关闭结果 channel。以下是推荐实现:
package main
import (
"fmt"
"sync"
)
func execTask(input int, results chan<p><strong>关键要点说明:</strong> </p>
-
sync.WaitGroup是轻量级同步原语,通过Add()、Done()和Wait()精确控制任务生命周期; -
close(results)必须由单个 goroutine 执行(本例中是匿名 goroutine),避免多处关闭 panic; - channel 缓冲(如
make(chan int, len(tasks)))非必需,但能防止 sender 在 receiver 尚未启动时阻塞(尤其当execTask极快时); -
for range results天然支持“边收边处理”,无需额外同步——Go 的 channel 保证了线程安全的数据传递; - 若需在处理结果时捕获错误或区分成功/失败,建议将
results改为结构体 channel(如chan struct{ Value int; Err error }),并在execTask中统一发送。
此模式广泛适用于批处理外部命令、HTTP 请求聚合、分布式任务分发等场景,兼顾实时性与终态可控性。










