zoukankan      html  css  js  c++  java
  • EasyDSS开发中Go语言在for循环中使用协程的注意点

    之前我们介绍过EasyDSS开发中对野协程的管理,有兴趣的朋友可以了解一下:EasyDSS协程出现panic并导致程序退出,如何对野协程进行管理?在 EasyDSS 的程序开发中,有时为了加快速度,会在 for 循环中采用协程的方式进行代码编写,类似代码如下:

    wg := sync.WaitGroup{}
    wg.Add(length)
    for s := range group.rtcSubSessionSet {
       //s.WriteRtcPacket(pkt)
       go func() {
          defer wg.Done()
          s.WriteRtcPacket(pkt)
       }()
    }
    wg.Wait()
    
    

    以上代码 s 为从集合中取出的指针变量,因为采用协程的方式, go func(){} 代码会新启动一个协程进行运行。for 循环进入下一次循环,此时 s 的值被改变,因此会导致发的包会乱序。因此修改代码如下:

    wg := sync.WaitGroup{}
    wg.Add(length)
    for s := range group.rtcSubSessionSet {
       //s.WriteRtcPacket(pkt)
       go func(sender *rtc.SubSession) {
          defer wg.Done()
    
          sender.WriteRtcPacket(pkt)
       }(s)
    }
    wg.Wait()
    

    以上代码将前一个指针变量以传递参数的方式传递到协程中,即使下一次循环中 s 改变,也不会出现问题。

    以上代码可以正常运行,但是如果协程中出现 panic 错误,就会导致整个程序退出,导致系统不稳定,因此我们进一步优化代码如下:

    wg := sync.WaitGroup{}
    wg.Add(length)
    for s := range group.rtcSubSessionSet {
       //s.WriteRtcPacket(pkt)
       go func(sender *rtc.SubSession) {
          defer func() {
             if err := recover(); err != nil {
                log.Error(fmt.Sprintf("panic %s
    ", err))
                log.Error(fmt.Sprintf(string(debug.Stack())))
             }
          }()
          defer wg.Done()
    
          sender.WriteRtcPacket(pkt)
       }(s)
    }
    wg.Wait()
    

    在代码的最开始加上 recover() 函数捕获所有的 panic 信息,这样既可以知道哪里出错,也能保证程序稳定运行。

    总结以下在写协程的时候主要注意两点:

    1.保证捕获协程中的 panic 异常;
    2.在协程中使用外部的变量时,应该以传参的方式传递到协程中。

  • 相关阅读:
    Linux-安装FFmpeg
    博客园添加视频
    博客园添加音乐
    通过容器提交镜像(docker commit)以及推送镜像(docker push)笔记
    根据不同配置.env获取不同的配置文件的配置
    1M大概多少个字
    计算机存储单位
    DNS原理及其解析过程
    查看到百度经过了多少个网关
    C语言的本质(18)——函数的可变参数
  • 原文地址:https://www.cnblogs.com/easydss/p/15525256.html
Copyright © 2011-2022 走看看