前言

今天发现了一个问题是之前一直没有注意到的,这里记一下

正文

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导致的问题的更多相关文章

  1. 记一次因证书问题导致请求失败问题SSLHandshakeException

    记一次因证书问题导致请求失败问题SSLHandshakeException 转载请注明出处:https://www.cnblogs.com/funnyzpc/p/10989813.html 最近接一外 ...

  2. 捉虫记(四)线程安全导致的HighCpu

    一个朋友QQ群里说网站启动后会cpu很高,想要帮忙看一下dump. 1.打开windbg加载dump文件后第一个命令lmf,这个命令显示加载的dll以及路径,这样子可以找个dll来帮忙加载sos,(额 ...

  3. 记因PHP的内存溢出导致的事故之解决

    如果对您有用记得关注,更多干货. 今天上午刚到公司,就有同事在公司群里反映某个计划任务出现问题了.我就怀着刨根问底的心,去查看了log.发现挺有意思的一个问题,PHP内存溢出导致脚本执行失败.那就一起 ...

  4. 记一次IIS发布网站导致系统时常跳入登录页面的问题解决

    服务器:winserver2012R2 iis 发布网站后,正常浏览网页,时常跳到登录页面,第一反应session过期,因为登录信息都存在session,但session 都是默认配置过期时间为20分 ...

  5. 飞机找不到,流量哪去了?记一次移动WAP网关导致的问题

    这几天随着客户端一个新版本发布,运维发现CDN的流量猛跌: 话说流量就是金钱,流量就是工资.领导很生气,后果很严重.没什么好说的,赶紧查!一开始怀疑服务端有问题,先受伤的总是我们,当然这也是没错的,因 ...

  6. 记一次JPA查询分页导致的数据丢失问题

    使用JPA查询,共17条数据,每页10条数据. 第一页与第二页有一条重复的数据,导致丢失一条数据 后查明原因发现,该查询使用了排序,排序字段的值在多条数据中相同,比如在3-11条是相同的值.此时跳到第 ...

  7. 记一次内存无法回收导致频繁fullgc机器假死的思路

    确定挂机 络绎不绝的来不同类型的bug 当bug滚滚而来时,不要怀疑,你的发布的应用基本是不可用状态了.观察哨兵监控数据,特别是内存打到80%基本就挂机了,或者监控数据缺失也基本是挂机了.此时应当马上 ...

  8. 记-ItextPDF+freemaker 生成PDF文件---导致服务宕机

    摘要:已经上线的项目,出现服务挂掉的情况. 介绍:该服务是专门做打印的,业务需求是生成PDF文件进行页面预览,主要是使用ItextPDF+freemaker技术生成一系列PDF文件,其中生成流程有:解 ...

  9. 记一次Apache的代码导致生产服务耗时增加

    引言 二狗:二胖快醒醒,赶紧看看刚才报警邮件,你上次写的保存用户接口耗时(<二胖的参数校验坎坷之路>)大大上升,赶紧排查下原因. 二胖:好的,马上看,内心戏可十足(心里却在抱怨,大中午的搅 ...

随机推荐

  1. 5+App 相关记录

    一.页面跳转到app 1.应用的manifest.json文件,plus --> distribute --> google 节点下,增加属性 schemes 2.打包后,在手机里安装. ...

  2. git 远端版本回退

    情景:本地更改推送远端后,想要回退到自己推送之前的某个版本. 比如想回退的分支为 test 分支. 风险:远端回退到某一版本后,之后的所有推送都没了(对应的日志记录也没了).如果是团队开发,不仅自己推 ...

  3. C++笔试题续

    第一部分:C++与C语言的差异(1-18)1.C 和 C++ 中 struct 有什么区别? Protection行为 能否定义函数C 无 否,但可以有函数指针C++ 有 可以,默认是public2. ...

  4. 如何写好PPT,什么样的PPT容易被人理解记住

    PPT一般是用于讲解性的行为而存在,那如果写好PPT呢?如果写好,这个完全要取决于你所面向的目标读者,是用于学术行为呢?还是用于商业行为.面对不同的目标群体,有不同的策略.但是无论面向群体是谁我们都有 ...

  5. 03-flask-视图函数基础

    代码 from flask import Flask, request, url_for, jsonify, redirect # 创建Flask对象 app = Flask(__name__) @a ...

  6. 统计文件行数,推荐使用LineNumberReader

    一.主题: 读取文本文件最大行数性能比较:lineNumberReader > Files.lines 二.code 1 @Test 2 public void testLineReader() ...

  7. 多任务-python实现-使用队列完成进程间的通信(2.1.8)

    @ 目录 1.为什么要使用队列 2.python代码实现 1.为什么要使用队列 进程之间是互相独立的,而线程能够共享全局变量 所以如果进程间想要交换数据的话 只有通过进程间的通信,比如socket.太 ...

  8. xss靶场练习(7.22)

    靶场地址:http://xss.fbisb.com/ 参考的文章:https://www.cnblogs.com/cute-puli/p/10834954.html  感谢大佬的分享 做这个题的思路就 ...

  9. 微信小程序手机号解密失败-43001

    今天是2020年1月16号,从昨天下午开始,一直遇到一个问题: 客户在注册会员的时候的第二步,验证手机号的时候,一直提示验证失败,-43001 直接说原因:用户的session_key过期 期间大部分 ...

  10. [Python] iupdatable包使用说明

    iudatable包是我对常用函数进行的封装后发布的一个python包. 安装 iupdatable 包 pip install iupdatable 更新 iupdatable 包 pip inst ...