文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2024-04-02 19:55

关注

什么时候会导致死锁

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

发送单个值时的死锁

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


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泄露内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯