用 WaitGroup + channel 实现批量并发任务
发布时间 - 2026-01-29 00:00:00 点击率:次WaitGroup 负责等待所有 goroutine 结束,channel 负责传递结果或协调节奏;正确做法是启动前 wg.Add(n),每个 goroutine 结尾 defer wg.Done() 后再发结果到 channel,并在所有发送完成后关闭 channel。
WaitGroup 和 channel 各自该管什么
WaitGroup 负责“等所有 goroutine 结束”,channel 负责“传结果或协调节奏”。混用时最常见错误是:用 channel 去替代 WaitGroup 的等待逻辑,比如反复 range 一个未关闭的 channel 导致死锁,或者漏掉 wg.Done() 还指望从 channel 收完就自动退出。
正确分工:wg.Add() 在启动 goroutine 前调用;每个 goroutine 结尾必须调用 wg.Done()(最好用 defer);channel 仅用于输出结果、限流或通知完成,不承担生命周期管理职责。
并发任务结果收集的典型写法
批量任务通常需要汇总返回值,这时 channel 是自然选择,但必须配合 WaitGroup 确保所有发送完成后再关闭 channel。否则消费者可能提前退出,漏收数据。
- 启动前
wg.Add(n),n 是任务总数 - 每个 goroutine 执行完后
defer wg.Done(),再向 channel 发送结果(如ch ) - 另起一个 goroutine 调用
wg.Wait(),然后close(ch) - 主 goroutine 用
for range ch安全接收,无需担心 channel 未关闭
ch := make(chan int, 10) wg :=&sync.WaitGroup{} for i := 0; i < 5; i++ { wg.Add(1) go func(id int) { defer wg.Done() ch <- id * 2 }(i) } go func() { wg.Wait() close(ch) }() for res := range ch { fmt.Println(res) }
为什么不能只用 channel 不用 WaitGroup
只靠 close(ch) 并不能保证所有 goroutine 已执行完毕——你可能在某个 goroutine 还没走到 ch 那行时就关闭了 channel,导致它 panic:send on closed channel。反过来,如果不用 channel 而只用 wg.Wait(),又拿不到中间结果。
关键点在于:WaitGroup 保证“执行结束”,channel 保证“通信安全”。二者不是替代关系,而是互补关系。尤其当任务耗时差异大、部分失败需继续执行其余任务时,这种组合能避免过早关闭 channel 或遗漏结果。
容易被忽略的缓冲区和关闭时机
channel 缓冲区大小设太小会导致 goroutine 阻塞在发送端,拖慢整体进度;设太大则浪费内存。更隐蔽的问题是关闭 channel 的 goroutine 可能比所有 worker 启动得还慢,造成竞态。
- 缓冲区建议设为任务数
cap(ch) == n,或略大(如n+1),避免阻塞 -
close(ch)必须在wg.Wait()之后,且只能由一个 goroutine 执行 - 不要在 worker 内部判断 “我是最后一个” 然后关 channel —— 没有可靠方式识别“最后一个”
- 如果任务可能 panic,
defer wg.Done()仍有效,但需额外 recover,否则 channel 不会关闭
实际项目里,真正难的不是写对这几行,而是想清楚:哪些数据必须按序收?哪些可以丢?失败要不要重试?这些决策会直接决定 channel 类型(带缓冲/无缓冲)、是否用带超时的 select、以及是否引入 error channel。
# go
# ai
# golang
# 并发
# channel
# 死锁
# 我是
# 自然选择
# 完成后
# 还没
# 走到
# 设为
# 并在
# 不承担
# 能在
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
网站制作企业,网站的banner和导航栏是指什么?
用yum安装MySQLdb模块的步骤方法
想要更高端的建设网站,这些原则一定要坚持!
Laravel如何优雅地处理服务层_在Laravel中使用Service层和Repository层
Laravel怎么防止CSRF攻击_Laravel CSRF保护中间件原理与实践
PHP 500报错的快速解决方法
深圳网站制作的公司有哪些,dido官方网站?
Laravel Docker环境搭建教程_Laravel Sail使用指南
php后缀怎么变mp4格式错误_修改扩展名提示格式不对怎么办【技巧】
如何用PHP快速搭建CMS系统?
Laravel怎么使用Session存储数据_Laravel会话管理与自定义驱动配置【详解】
如何在新浪SAE免费搭建个人博客?
Laravel Blade组件怎么用_Laravel可复用视图组件的创建与使用
Laravel路由怎么定义_Laravel核心路由系统完全入门指南
千问怎样用提示词获取健康建议_千问健康类提示词注意事项【指南】
php打包exe后无法访问网络共享_共享权限设置方法【教程】
如何在腾讯云服务器快速搭建个人网站?
高端云建站费用究竟需要多少预算?
Laravel用户密码怎么加密_Laravel Hash门面使用教程
浏览器如何快速切换搜索引擎_在地址栏使用不同搜索引擎【搜索】
如何用PHP工具快速搭建高效网站?
青岛网站建设如何选择本地服务器?
Swift中switch语句区间和元组模式匹配
iOS中将个别页面强制横屏其他页面竖屏
油猴 教程,油猴搜脚本为什么会网页无法显示?
如何用IIS7快速搭建并优化网站站点?
Laravel如何为API编写文档_Laravel API文档生成与维护方法
如何在服务器上配置二级域名建站?
Laravel如何升级到最新版本?(升级指南和步骤)
Laravel广播系统如何实现实时通信_Laravel Reverb与WebSockets实战教程
Laravel怎么判断请求类型_Laravel Request isMethod用法
Laravel如何处理文件上传_Laravel Storage门面实现文件存储与管理
香港服务器建站指南:外贸独立站搭建与跨境电商配置流程
如何在阿里云虚拟服务器快速搭建网站?
Laravel如何使用缓存系统提升性能_Laravel缓存驱动和应用优化方案
重庆市网站制作公司,重庆招聘网站哪个好?
Laravel Sail是什么_基于Docker的Laravel本地开发环境Sail入门
JavaScript模板引擎Template.js使用详解
Javascript中的事件循环是如何工作的_如何利用Javascript事件循环优化异步代码?
百度浏览器如何管理插件 百度浏览器插件管理方法
Laravel怎么实现微信登录_Laravel Socialite第三方登录集成
EditPlus中的正则表达式 实战(1)
儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?
Laravel如何优化应用性能?(缓存和优化命令)
如何选择可靠的免备案建站服务器?
如何在建站之星网店版论坛获取技术支持?
如何用好域名打造高点击率的自主建站?
Win11关机界面怎么改_Win11自定义关机画面设置【工具】
购物网站制作费用多少,开办网上购物网站,需要办理哪些手续?
如何在香港免费服务器上快速搭建网站?


