Go并发编程之常见并发bug

本文讨论了Go语言中八大常见的并发编程错误,包括死锁、goroutine泄露、waitgroup使用不当、闭包捕获变量、waitgroup与goroutine启动顺序、多次关闭channel、并发读写map以及未限制goroutine数量。对于这些问题,提出了相应的解决策略,如使用sync.map、控制goroutine数量等。此外,还提到了Go的并发检测工具以及第三方协程池库的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 注意:下述所有图片中 - 号是BUG代码,+号是修复BUG的代码

1.死锁

goroutine1 ch发送者被阻塞住,无法释放锁

goroutine2 loop获取锁失败

 

2.goroutine永久泄露

 context.WithCancel内部启动goroutine,在ctx被覆盖后goroutin永久泄露

3.waitgroup使用不当,永久阻塞

使用WaitGroup一定要遵守的原则就是,等所有的Add方法调用之后再调用Wait否则可能导致panic或者不期望的结果

4.闭包捕获本地变量

5.goroutine启动前要保证waitgroup.Add完成

6.多次关闭同一个channel

 关闭已经关闭的channel会导致panic,因此在并发编程中要处理好channel的关闭

7.map 并发读写

这个bug无法被recover

线上做好supervisor和stderr重定向到文件,不然两眼一抹黑

共享资源竞争的问题,非常复杂,并且难以察觉,好在 Go 为我们提供了一个工具帮助我们检查,这个就是go build -race 命令。在项目目录下执行这个命令,生成一个可以执行文件,然后再运行这个可执行文件,就可以看到打印出的检测信息。

并发场景下考虑使用:sync.map

8.不控制gouroutine数量

这个例子实现了 math.MaxInt32 个协程的并发,约 2^31 = 2 亿个

运行会直接导致:​panic: too many concurrent operations on a single file or socket (max 1048575)

不同的应用程序,消耗的资源是不一样的。比较推荐的方式的是:应用程序来主动限制并发的协程数量。

  • 利用缓冲信道实现[2]

  • make(chan struct{}, 3) 创建缓冲区大小为 3 的 channel,在没有被接收的情况下,至多发送 3 个消息则被阻塞。
  • 开启协程前,调用 ch <- struct{}{},若缓存区满,则阻塞。
  • 协程任务结束,调用 <-ch 释放缓冲区。
  • sync.WaitGroup 并不是必须的,例如 http 服务,每个请求天然是并发的,此时使用 channel 控制并发处理的任务数量,就不需要 sync.WaitGroup。 

References

1.如何优雅地关闭通道

2.Go高性能编程之并发编程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值