zoukankan      html  css  js  c++  java
  • 如何安全close go 的channel

    golang 在多协程下,  不清楚谁是 sender 谁是 recver 的时候, close(chan) 和 chan<-data 两个都很容易报错

     原则:

    //1  close 永远和data分离, 不要close 还会发送或接受的 channel
    //2  close 永远要做好 'close of closed channel' 错误的发生
    //3  send (也就是 <- 操作) 永远不要让他出现 'send to a nil channel' 其实也就是第一点

    那么close 到底怎么才能更安全,更正确的,解决呢? 

    单协程 直接close ,太low,我们不考虑,只考虑最复杂环境下的情况.

     第一种方法 暴力关闭channel ,只需要增加 recover() 就可以了

    第二种方法  通过对变量加锁,或者直接使用sync.Once 来控制 close 只有一次

     第三种方法 创建两个chan,一个永远不close,只进行 无限 发送,  单个接收; 一旦接收了 ,就关闭另外一个; 另外一个 返还给外部, 只判断 close的情况,不进行发送和直接close

    第四种方法 比较简单,总是 使用select就可以了,

    done := make(chan struct{})

    // 复杂环境下 并发 进行关闭
    select{
          case <-done:
          default:
                    close(done)
    }

     

    //复杂环境 并发 检测是否关闭
    
    
    select{
          case <-done
                 //关闭处理
                 return 
           default:
                //没有关闭的处理
    }
    
    

     经过高并发测试,发现 上面的select 关闭方法, 还是不安全, select不是原子性, 只要异步 数量达到值,就还是会有出现panic的情况;

    测试用例:

     运行  Test_SafeCloseChan2   几乎是必现的,只不过是  成功 END 出现几次罢了.

    func Test_SafeCloseChan2(t *testing.T) {
        for i := 0; i < 1000; i++ {
            Test_SafeCloseChan(t)
        }
    }
    func Test_SafeCloseChan(t *testing.T) {
        done := make(chan bool)
        begin := time.Now().Add(300 * time.Millisecond)
        wg := sync.WaitGroup{}
        for i := 0; i < 1000000; i++ {
            wg.Add(1)
            go func(i int) {
                defer func() {
                    wg.Done()
                }()
                //等待开始,一起开始,避免不同时
                for {
                    if time.Now().After(begin) {
                        break
                    }
                    time.Sleep(1 * time.Microsecond)
                }
    
                select {
                case <-done:
                    //case <-time.After(500 * time.Millisecond):
                    //    select {
                    //    case <-done:
                    //    default:
                    //        close(done)
                    //        t.Log("Success close(done)")
                    //    }
                    //case <-time.After(500 * time.Millisecond):
                    //    t.Log("Success close(done)")
                    //    close(done)
                default:
                    close(done)
                    t.Log("Success close(done)")
                }
            }(i)
        }
        wg.Wait()
        t.Log("=============END=========")
    }

    所以, 还是加 panic 吧

    https://zhuanlan.zhihu.com/p/32529039

  • 相关阅读:
    Balanced Binary Tree
    Convert Sorted List to Binary Search Tree
    Convert Sorted Array to Binary Search Tree
    Binary Tree Zigzag Level Order Traversal
    Validate Binary Search Tree
    Binary Tree Level Order Traversal II
    Binary Tree Level Order Traversal
    Maximum Depth of Binary Tree
    如何把U盘的两个盘或者多个盘合成一个
    bugku 想蹭网先解开密码
  • 原文地址:https://www.cnblogs.com/ayanmw/p/14150576.html
Copyright © 2011-2022 走看看