记一次Goroutine与wg导致的问题
前言
今天发现了一个问题是之前一直没有注意到的,这里记一下
正文
Send Closed Chan
问题概述
代码逻辑是启动时启动多个 channel, channel1 获取数据监听数据处理后发送给 channel2 , channel2 处理后再给 channel3 等等
在 channel1 写完数据后将通道 channel1 关闭, channel1 关闭后 channel2 也关闭, 达到任务执行完毕后通道全部关闭的效果
我之前的代码是
func StartVerify() {
wg := sync.WaitGroup{}
for {
data, ok := <-TypicalResChan
if !ok {
wg.Wait()
close(VerifyBossDNSChan)
break
}
go func() {
wg.Add(1)
ok := Verify(data)
if ok {
VerifyBossDNSChan <- data
}
wg.Done()
}()
}
}
后来使用中发现有时候会报 send closed channel 的错误,大佬看了一眼就发现了问题
问题剖析
就以上面的举例, 上游向 TypicalResChan 发送数据时, 如果不是 close 请求, 会启动一个 goroutine 去处理逻辑, 而在 启动这个 goroutine 后在内部进行 wg 的 Add 注册, 注意这个过程是有耗时的, 所以问题来了, 当上游向 TypicalResChan 发送 close 时, 进入 !ok 的逻辑, 此时等待 wg 释放, 此时有可能上一个数据接收到后还在启动一个 goroutine ,还没有 Add注册, 此时wg没有监听到这个 goroutine 的注册, 造成不会等待这个 goroutine ,直接就关闭了 TypicalResChan, 而这个 goroutine 执行后向 TypicalResChan 发送数据时 TypicalResChan 已经关闭, 所以会报错导致 panic
另外, 还需要注意的是在 wg 没有注册前就 wait 是不推荐的, 很容易出现问题
还有就是判断通道关闭更推荐使用 range 省去判断 !ok 的步骤保持代码整洁
问题解决
修改成这样即可
func StartVerify() {
wg := sync.WaitGroup{}
for data := range TypicalResChan {
wg.Add(1)
go func(data Result) {
defer wg.Done()
ok := Verify(data)
if ok {
VerifyBossDNSChan <- data
}
}(data)
}
wg.Wait()
close(VerifyBossDNSChan)
}
在上游 close 时 range 会自动结束, 而受到正常数据先 Add 防止时间差导致的 Add 失败问题, 在 1.14 后 go 优化了 defer 的逻辑, defer 基本不再有消耗, 所以推荐使用 defer 注册 wg 的关闭, 而在 close 时, for 循环结束, wg 在 wait 后再 close
记一次Goroutine与wg导致的问题的更多相关文章
- 记一次因证书问题导致请求失败问题SSLHandshakeException
记一次因证书问题导致请求失败问题SSLHandshakeException 转载请注明出处:https://www.cnblogs.com/funnyzpc/p/10989813.html 最近接一外 ...
- 捉虫记(四)线程安全导致的HighCpu
一个朋友QQ群里说网站启动后会cpu很高,想要帮忙看一下dump. 1.打开windbg加载dump文件后第一个命令lmf,这个命令显示加载的dll以及路径,这样子可以找个dll来帮忙加载sos,(额 ...
- 记因PHP的内存溢出导致的事故之解决
如果对您有用记得关注,更多干货. 今天上午刚到公司,就有同事在公司群里反映某个计划任务出现问题了.我就怀着刨根问底的心,去查看了log.发现挺有意思的一个问题,PHP内存溢出导致脚本执行失败.那就一起 ...
- 记一次IIS发布网站导致系统时常跳入登录页面的问题解决
服务器:winserver2012R2 iis 发布网站后,正常浏览网页,时常跳到登录页面,第一反应session过期,因为登录信息都存在session,但session 都是默认配置过期时间为20分 ...
- 飞机找不到,流量哪去了?记一次移动WAP网关导致的问题
这几天随着客户端一个新版本发布,运维发现CDN的流量猛跌: 话说流量就是金钱,流量就是工资.领导很生气,后果很严重.没什么好说的,赶紧查!一开始怀疑服务端有问题,先受伤的总是我们,当然这也是没错的,因 ...
- 记一次JPA查询分页导致的数据丢失问题
使用JPA查询,共17条数据,每页10条数据. 第一页与第二页有一条重复的数据,导致丢失一条数据 后查明原因发现,该查询使用了排序,排序字段的值在多条数据中相同,比如在3-11条是相同的值.此时跳到第 ...
- 记一次内存无法回收导致频繁fullgc机器假死的思路
确定挂机 络绎不绝的来不同类型的bug 当bug滚滚而来时,不要怀疑,你的发布的应用基本是不可用状态了.观察哨兵监控数据,特别是内存打到80%基本就挂机了,或者监控数据缺失也基本是挂机了.此时应当马上 ...
- 记-ItextPDF+freemaker 生成PDF文件---导致服务宕机
摘要:已经上线的项目,出现服务挂掉的情况. 介绍:该服务是专门做打印的,业务需求是生成PDF文件进行页面预览,主要是使用ItextPDF+freemaker技术生成一系列PDF文件,其中生成流程有:解 ...
- 记一次Apache的代码导致生产服务耗时增加
引言 二狗:二胖快醒醒,赶紧看看刚才报警邮件,你上次写的保存用户接口耗时(<二胖的参数校验坎坷之路>)大大上升,赶紧排查下原因. 二胖:好的,马上看,内心戏可十足(心里却在抱怨,大中午的搅 ...
随机推荐
- 题解-CF1444C Team-Building
题面 CF1444C Team-Building 给 \(n\) 个点 \(m\) 条边,每个点有颜色 \(c_i(1\le c_i\le k)\),求有多少个颜色对两组点并后是二分图. 数据范围:\ ...
- 在DLL中使用对话框
在 DLL 中使用对话框资源与在 EXE 中使用是有所区别的,处理不当便会造成断言失败.原因是因为 CDialog::Create 与 CreateEx 默认使用当前进程中的资源(Dialog Tem ...
- 三、Zookeeper简介
一.简介 zookeeper 主要使用场景:分布式系统的分布式协同服务.协同工作就是通过某种方式,让着节点的信息能够同步和共享,依赖于进程间的通信.通信方式有俩种. 通过网络进行信息共享 现实工作中, ...
- MVCAdmin项目知识点记录
1.在过滤器中,用ViewBag类似的东西,要((ViewResult)filterContext.Result).ViewBag. 2.Controller中自己定义的非Action方法中(包括构造 ...
- Python使用requests发送请求
Python使用第三方包requests发送请求,实现接口自动化 发送请求分三步: 1.组装请求:包括请求地址.请求头header.cookies.请求数据等 2.发送请求,获取响应:支持get.po ...
- 【Django Python版本对应】
使用Python36 时应该使用Django版本1.11.4 pip install django==1.11.4 版本对应表: Django version Python versions 1.8 ...
- Jetty web server 远程共享缓冲区泄漏漏洞学习
https://www.secpulse.com/archives/4911.html https://www.tiejiang.org/11628.html http://blog.gdssecur ...
- SpringBoot从入门到精通教程(二)
SpringBoot 是为了简化 Spring 应用的创建.运行.调试.部署等一系列问题而诞生的产物,自动装配的特性让我们可以更好的关注业务本身而不是外部的XML配置,我们只需遵循规范,引入相关的依赖 ...
- redis源码学习之lua执行原理
聊聊redis执行lua原理 从一次面试场景说起 "看你简历上写的精通redis" "额,还可以啦" "那你说说redis执行lua脚本的原理&q ...
- Linux工具包
Linux的工具包 JDK 版本:14 百度网盘:链接: https://pan.baidu.com/s/1hWqGVmsElOCBufMuscPXzw 密码:st3y 安装步骤: 1.使用S ...