Go中安全等待多个Goroutine完成并实时处理结果的方法
时间:2026-08-15 | 作者:星际追番人 | 阅读:0
本文讲解如何使用 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<- int) {
// 模拟耗时操作(如 os/exec.Run)
result := input * 2 // 示例计算结果
results <- result
}
func main() {
tasks := []int{1, 2, 3, 4, 5}
var wg sync.WaitGroup
results := make(chan int)
// 启动所有任务 goroutine,并注册 WaitGroup 计数
wg.Add(len(tasks))
for _, task := range tasks {
go func(t int) {
defer wg.Done() // 任务完成时递减计数
execTask(t, results)
}(task)
}
// 单独 goroutine 等待全部任务结束,并关闭 channel
go func() {
wg.Wait()
close(results) // 关键:关闭 channel,使 range 自动退出
}()
// 主 goroutine 实时接收并处理结果(无需等待全部完成)
for result := range results {
fmt.Printf("Received: %dn", result)
// 此处可立即处理每个结果:写入数据库、触发回调、聚合统计等
// 甚至可在此启动新 goroutine 进行后续异步处理
}
fmt.Println("All tasks completed.")
}关键要点说明:
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 中协调“多生产者、单消费者”场景的标准范式,兼顾安全性、简洁性与实时响应能力。
免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。
相关文章
更多-
- iOS Swift连续present多个页面报错或崩溃解决方法
- 时间:2026-08-21
-
- Dart中如何串联多个数据流实现流式处理
- 时间:2026-08-21
-
- SQL中COUNT DISTINCT统计多个字段的方法与写法
- 时间:2026-08-20
-
- 多个按钮如何分别绑定不同的dialog对话框实现方法
- 时间:2026-08-20
-
- GCC编译多个文件的命令写法与使用方法
- 时间:2026-08-20
-
- Spring项目多个Maven模块循环依赖问题分析与解决方法
- 时间:2026-08-20
-
- Clang编译多个文件找不到头文件的解决方法
- 时间:2026-08-18
-
- 多个来源网站列如何合并为单一列并保留其他字段信息
- 时间:2026-08-17
精选合集
更多大家都在玩
大家都在看
更多-
- 闪烁之光法师及坦克符文推荐
- 时间:2026-10-21
-
- 闪烁之光三灵系玩法解析
- 时间:2026-10-21
-
- 闪烁之光高速爆发流攻略
- 时间:2026-10-21
-
- 闪烁之光食魇天马和金羽鸾适配场景
- 时间:2026-10-21
-
- 闪烁之光永恒纪元钟效果解析
- 时间:2026-10-21
-
- 闪烁之光神装选择思路
- 时间:2026-10-21
-
- PS怎么用魔棒抠图
- 时间:2026-10-21
-
- OBS Studio怎么设置音频输入源
- 时间:2026-10-21
