zoukankan      html  css  js  c++  java
  • 记一次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

  • 相关阅读:
    [置顶] Android中使用sqlite3操作SQLite
    我们不应歧视任何语言,她们都是萌娘!(有图有真相)
    一牛人博客导航
    机器学习&数据挖掘笔记_14(GMM-HMM语音识别简单理解)
    机器学习&数据挖掘笔记_16(常见面试之机器学习算法思想简单梳理)
    机器学习、深度学习、数据挖掘各种资源整理
    MLP 之手写数字识别
    卷积神经网络CNN 手写数字识别
    支持向量机SVM 简要推导过程
    23种设计模式
  • 原文地址:https://www.cnblogs.com/chnmig/p/12744118.html
Copyright © 2011-2022 走看看