Go语言用goroutine+channel+sync.WaitGroup可安全实现并发任务调度:通过带缓冲channel限流、defer确保信号量归还、WaitGroup配合关闭channel收集结果,避免泄漏与死锁。

Go 语言本身不提供“任务队列”或“并发任务调度器”,但用 goroutine + channel + sync.WaitGroup 就能高效实现可控的并发任务处理——关键不在“并发多少”,而在“如何控制边界、捕获错误、避免 goroutine 泄漏”。
怎么用 goroutine 安全启动一批任务而不炸掉内存
直接 for 循环里起 go f() 很危险:任务量大时会瞬间创建成千上万个 goroutine,可能耗尽内存或压垮下游服务。必须限流。
- 用带缓冲的
chan struct{}当信号量,控制最大并发数(比如最多 10 个并发) - 每个任务开始前先
,结束时sem - 别忘了用
defer确保信号量归还,否则会卡死
sem := make(chan struct{}, 10)
for _, task := range tasks {
sem <- struct{}{} // 阻塞直到有空位
go func(t Task) {
defer func() { <-sem }() // 必须放 defer,防止 panic 后漏释放
process(t)
}(task)
}怎么等所有并发任务完成并收集结果
不能只靠 time.Sleep,也不能靠轮询。正确方式是组合 sync.WaitGroup 和 channel:
-
WaitGroup负责计数“谁还没完” - 结果通道(
chan Result)统一收数据,主 goroutine range 接收,配合close()退出 - 每个任务结束后调用
wg.Done(),并在所有任务启动后另起 goroutinewg.Wait()后关闭结果通道
results := make(chan Result, len(tasks)) var wg sync.WaitGroupfor _, task := range tasks { wg.Add(1) go func(t Task) { defer wg.Done() r := process(t) results <- r }(task) }
go func() { wg.Wait() close(results) }()
for r := range results { fmt.Println(r) }
为什么 range channel 会提前退出或卡住
常见错误是没在合适时机 close(results),导致 range 永远等不到 EOF;或者多个 goroutine 同时 close 同一个 channel,panic “close of closed channel”。
云模块_YunMOK网站管理系统采用PHP+MYSQL为编程语言,搭载自主研发的模块化引擎驱动技术,实现可视化拖拽无技术创建并管理网站!如你所想,无限可能,支持创建任何网站:企业、商城、O2O、门户、论坛、人才等一块儿搞定!永久免费授权,包括商业用途; 默认内置三套免费模板。PC网站+手机网站+适配微信+文章管理+产品管理+SEO优化+组件扩展+NEW Login界面.....目测已经遥遥领先..
立即学习“go语言免费学习笔记(深入)”;
- 只能由**单一 goroutine** 关闭结果 channel,且必须在所有发送者都退出后
- 用
sync.WaitGroup是最稳妥的判断依据——wg.Wait()返回后才close - 如果某个任务 panic,
defer wg.Done()仍会执行,不影响计数,但结果不会发出(需加 recover 或用 err channel 补偿)
要不要用第三方库比如 ants 或 errgroup
简单场景不需要。标准库完全够用:errgroup.Group 可以简化错误传播和等待逻辑,适合需要“任一失败就取消全部”的场景;ants 提供复用 goroutine 的池,但多数 IO 密集型任务并不需要——goroutine 本身开销极小,瓶颈通常在 IO 或业务逻辑。
- 优先用
errgroup.WithContext替代手写WaitGroup+context取消 - 除非你明确观测到 goroutine 创建/销毁成为性能瓶颈(pprof 看
runtime.malg),否则别过早引入池化 - 注意
ants.Submit是同步阻塞调用,不是启动 goroutine 的快捷方式
真正难的从来不是“怎么并发”,而是“怎么让并发不变成事故”——信号量漏发、channel 没关、panic 没 recover、context 没传递……这些细节错一个,程序就在线上安静地出问题。









