我故意写了这样一段代码来引起死锁和随后的恐慌抛出:
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("Start:", time.Now())
channel1 := make(chan string, 2)
channel1 <- "Cat"
channel1 <- "Dog"
limiter := time.NewTicker(time.Millisecond * 500)
for channel1Item := range channel1 {
<-limiter.C
fmt.Println(channel1Item)
}
fmt.Println("End:", time.Now())
}
字符串
在某种程度上,死锁确实会发生,代码只是无限期地挂起,但是,它不会引发恐慌。如果我删除限制器(股票代码),它就会这样做。为什么自动收报机能防止恐慌被抛出?
我目前正在学习Go,当我改变随机位以满足我的好奇心时,我无意中遇到了这个例子。奇怪的行为(一个恐慌不被抛出)发生在我决定不关闭通道,看看会发生什么。
我知道在一个没有被馈送的开放通道上测距通常会引发恐慌,但似乎在循环中有一个自动收报机会中断恐慌引发行为。
2条答案
按热度按时间yuvru6vn1#
因为GO中的判断是,当一个goroutine试图在一个封闭的通道上发送一条有价值的消息时,它会触发恐慌。
在您的代码中,您没有关闭channel 1,因此循环将无限期地等待channel 1接受该值。<-限制器。C会周期性地向通道发送值因此channel 1不会排除panic,带有限制器的循环将挂起即使他没有任何新值
希望能对你有所帮助
sh7euo9m2#
我知道在一个没有被喂食的开放通道上测距通常会引发恐慌
我猜这是正确的,如果“在开放通道上测距”是唯一发生的事情(或者所有其他goroutine也被阻塞),就会检测到死锁(并触发恐慌)。将在此(playground)中检测到死锁:
字符串
但不是在这个(playground)中:
型
这是因为,当
for _ = range c {
被阻塞时,goroutine没有阻塞(所以没有死锁)。识别死锁的代码相对简单,如果没有任何东西可以运行,就会触发死机。它不会检查正在运行的代码是否在做有用的事情!
根据Ticker的文档:
自动收报机将调整时间间隔或下降滴答,以弥补缓慢的接收器。
无论频道上是否有监听,自动收报机都将继续运行;这类似于在代码中添加以下内容(playground):
型
无论
channel2
上是否有监听对象,这个循环都会继续运行。因此,不会检测到死锁(也不会触发死机)。添加Ticker
具有相同的影响; X1 M3 N1 X正在运行的事实意味着将不会检测到死锁。