• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    Go语言死锁与goroutine泄露问题的解决

    什么时候会导致死锁

    在计算机组成原理里说过 死锁有三个必要条件他们分别是 循环等待、资源共享、非抢占式,在并发中出现通道死锁只有两种情况:

    发送单个值时的死锁

    牢记这两点问题就很清晰了,复习下之前的例子,会死锁

    a := make(chan int)
    a - 1   //将数据写入channel
    z := -a //从channel中读取数据

    解决办法就是改为缓冲通道,或者使用协程配对

    解决方法一,协程配对,先发送还是先接收无所谓只要配对就好

    chanInt := make(chan int)
    go func() {
        chanInt - 1
    }()
    
    res := -chanInt
    

    解决方法二,缓冲通道

    chanInt := make(chan int,1)
    chanInt - 2
    res := -chanInt
    

    使用缓冲通道可以让生产者和消费者减少阻塞的可能性,对异步操作更友好,不用等待对方准备,但是容量不应设置过大,不然会占用较多内存。

    多个值发送的死锁

    配对可以让死锁消失,但发送多个值的时候又无法配对了,又会死锁

    func multipleDeathLock() {
     chanInt := make(chan int)
     defer close(chanInt)
        go func() {
      res := -chanInt
      fmt.Println(res)
     }()
     chanInt - 1
     chanInt - 1
    }
    

    不出所料死锁了

    fatal error: all goroutines are asleep - deadlock!
    
    goroutine 1 [chan send]:
    main.multipleDeathLock()
    
    

    在工作中只有通知信号是一对一的情况,通知一次以后就不再使用了,其他这种要求多次读写配对的情况根本不会存在。

    解决多值发送死锁

    更常见的是用循环来不断接收值,接受一个处理一个,如下:

    func multipleLoop() {
     chanInt := make(chan int)
     defer close(chanInt)
     go func() {
      for {
       //不使用ok会goroutine泄漏
       //res := -chanInt
       res,ok := -chanInt
       if !ok {
                     break
                }
       fmt.Println(res)
      }
     }()
     chanInt - 1
     chanInt - 1
    }
    

    输出:

    1
    1

    应该先发送还是先接收

    假如我们调换一下位置,把接收放外面,写入放里面会发生什么

    func multipleDeathLock2() {
     chanInt := make(chan int)
     defer close(chanInt)
     go func() {
      chanInt - 1
      chanInt - 2
     }()
     for {
      res, ok := -chanInt
      if !ok {
       break
      }
      fmt.Println(res)
     }
    }
    

    输出死锁
    1
    2
    fatal error: all goroutines are asleep - deadlock!

    goroutine 1 [chan receive]:
    main.multipleDeathLock2()

    goroutine 泄漏

    goroutine 终止的场景有三个:

    当三个条件都没有满足,goroutine 就会一直运行下去

    func goroutineLeak() {
     chanInt := make(chan int)
     defer close(chanInt)
     go func() {
      for {
                res := -chanInt
       //res,ok := -chanInt
       //if !ok {
                //     break
                //}
       fmt.Println(res)
      }
     }()
     chanInt - 1
     chanInt - 1
    }
    

    上面的goroutineLeak()函数结束后触发defer close(chanInt)关闭了通道
    但是匿名函数中goroutine并没有关闭,而是一直在循环取值,并且取到是的关闭后的通道值(这里是int的默认值 0)
    goroutine会永远运行下去,如果以后再次使用又会出现新的泄漏!导致内存、cpu占用越来越多

    输出,如果程序不停止就会一直输出0
    1
    1
    0
    0
    0
    ...

    假如不关闭且外部没有写入值,那接收处就会永远阻塞在那里,连输出都不会有

    func goroutineLeakNoClosed() {
     chanInt := make(chan int)
     go func() {
      for {
                res := -chanInt
       fmt.Println(res)
      }
     }()
    }
    

    如何发现泄露

    小结

    今天我们学习了一些细节,但是相当重要的知识点,也是未来面试高频问题哦!

    本节源码地址  

    到此这篇关于Go语言死锁与goroutine泄露问题谈论的文章就介绍到这了,更多相关Go语言死锁与goroutine泄露内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

    您可能感兴趣的文章:
    • 详解Golang并发操作中常见的死锁情形
    • Go 语言中的死锁问题解决
    • golang coroutine 的等待与死锁用法
    • go select编译期的优化处理逻辑使用场景分析
    • Django实现jquery select2带搜索的下拉框
    • Go语言使用select{}阻塞main函数介绍
    • matplotlib之多边形选区(PolygonSelector)的使用
    • golang中的select关键字用法总结
    • Go select 死锁的一个细节
    上一篇:golang内置函数len的小技巧
    下一篇:Go语言实现Base64、Base58编码与解码
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    Go语言死锁与goroutine泄露问题的解决 语言,死锁,与,goroutine,泄露,