记一次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的代码导致生产服务耗时增加
引言 二狗:二胖快醒醒,赶紧看看刚才报警邮件,你上次写的保存用户接口耗时(<二胖的参数校验坎坷之路>)大大上升,赶紧排查下原因. 二胖:好的,马上看,内心戏可十足(心里却在抱怨,大中午的搅 ...
随机推荐
- javascript编写原则
1.不要在同一行声明多个变量2.使用===或!==来比较3.使用字面量的方式来创建对象.数组,替代new Array这种形式4.switch语句必须要带default分支5.fon-in循环中的变量, ...
- tomcat-1-介绍篇
java语言分为三个体系: javase javaee,是javase的基础 一般就是指jdk javaee java的企业版本 其实是一套规范,就是用java语言做企业开发(目前看来就是开发一些动态 ...
- 我的js公共函数合集
export default { isDefin: function(value) { //数据是否被定义 if (value == null || value == &quo ...
- oracle使用rman备份集恢复方式创建ADG
一.背景 系统: 主库:rhel 6.4 64bit 备库:rhel 6.4 64bit 内存:2G [oracle@dgdb1 ~]$ free -m total used free share ...
- 马赛克密码破解——GitHub 热点速览 Vol.50
作者:HelloGitHub-小鱼干 "xx"(爆粗口) 这个词是最能体现本人看到本周 GitHub 热点的心情的.那一天,看到用图片处理技术还原马赛克密码的 Depix 便惊为天 ...
- 升级jenkins之后无法启动 报错Unable to read /var/lib/jenkins/config.xml
故障记录 点击jenkins升级后再点击回滚到之前版本,jenkins就起不来了. 欲哭无泪,报错如下 hudson.util.HudsonFailedToLoad: org.jvnet.hudson ...
- 第一次软件工程与UML的编程作业
博客班级 https://edu.cnblogs.com/campus/fzzcxy/2018SE1/ 作业要求 https://edu.cnblogs.com/campus/fzzcxy/2018S ...
- vue插值 v-cloak
vue插值 v-cloak 使用VUE时,页面刷新时会出现闪动的现象(即在插值时会显示两侧的 {}) 先定义一个VUE 通过选择器在style中定义v-cloak的display值为none 再在元素 ...
- [EF] - Code First处理Clustered Index
Clustered Index <=>集群索引: http://msdn.microsoft.com/en-us/library/ms177443.aspx 由于其特殊性,使得每个tabl ...
- 测试常用sql语句
一.查询数值型数据:SELECT * FROM tb_name WHERE sum > 100;查询谓词:>,=,<,<>,!=,!>,!<,=>,=& ...