遍历未关闭通道引发死锁却未触发Panic?计时器为何影响该行为
为什么Go中计时器会阻止死锁Panic?
首先要明确Go的死锁触发逻辑:Go的死锁panic只会在所有goroutine都处于阻塞状态,且没有任何goroutine能继续推进程序执行时才会触发。
无计时器的场景
移除计时器后,程序执行流程如下:
- 向缓冲通道
channel1存入两个元素 for range遍历通道,取完两个元素后,会持续阻塞在channel1的读取操作上(通道未关闭,遍历会一直等待新数据)- 此时程序中只有
main这一个goroutine,它完全阻塞,没有其他goroutine能运行,满足死锁检测条件,因此Go runtime触发死锁panic。
有计时器的场景
保留计时器时,关键差异在于time.NewTicker的行为:
time.NewTicker会启动一个后台goroutine,这个goroutine会按设定的500ms间隔,持续向limiter.C通道发送时间值- 当
maingoroutine取完channel1的两个元素后,会阻塞在channel1的读取上,但后台的计时器goroutine仍在正常运行(不断生成时间事件发送到limiter.C) - 因为存在活跃的goroutine(计时器的后台goroutine),Go runtime判定程序还有继续执行的可能,不会触发死锁panic,程序因此无限挂起。
额外补充:如果在代码中调用limiter.Stop(),会停止计时器的后台goroutine,此时所有goroutine都进入阻塞状态,程序就会触发死锁panic。
内容的提问来源于stack exchange,提问作者Mitlandir
相关产品推荐
相关产品推荐

