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.在协程中使用外部的变量时,应该以传参的方式传递到协程中。

  • 相关阅读:
    AtCoder Beginner Contest 167
    AtCoder Beginner Contest 166
    AtCoder Beginner Contest 165
    AtCoder Beginner Contest 164
    AtCoder Beginner Contest 163
    AtCoder Beginner Contest 162
    AtCoder Beginner Contest 161
    AtCoder Beginner Contest 160
    AtCoder Beginner Contest 159
    自定义Mybatis自动生成代码规则
  • 原文地址:https://www.cnblogs.com/easydss/p/15525256.html
Copyright © 2011-2022 走看看