package main
import (
"fmt"
"time"
)
func main() {
p := producer()
for c := range p {
fmt.Println(c)
}
}
func producer() <-chan string {
ch := make(chan string)
go func() {
for i := 0; i < 5; i++ {
ch <- fmt.Sprint("hello", i)
time.Sleep(1 * time.Second)
}
// commented the below to show the issue
// close(ch)
}()
return ch
}
运行上面的代码将打印 5 条消息,然后给出“all goroutine are sleep - deadlock error”。我知道如果我关闭通道,错误就会消失。
我想了解的是 go 运行时如何知道代码将在通道上无限等待并且没有其他任何东西会将数据发送到通道中。
现在,如果我向 main() 函数添加一个额外的 go 例程..它不会抛出任何错误并继续在通道上等待。
go func() {
for {
time.Sleep(2 * time.Millisecond)
}
}()
那么这是否意味着...... go 运行时只是寻找正在运行的 go 例程是否存在,该例程可能会将数据发送到通道中,因此不会引发死锁错误?
如果您想更深入地了解 Go 如何实现死锁检测,请查看代码中抛出以下错误的位置:"all goroutines are asleep - deadlock!"
: https://github.com/golang/go/blob/master/src/runtime/proc.go#L3751 https://github.com/golang/go/blob/master/src/runtime/proc.go#L3751
看起来 Go 运行时对有多少个 goroutine、有多少个空闲 goroutine 以及有多少个 goroutine 正在休眠以获取锁进行了一些相当简单的统计(不确定通道 I/O 上的哪个休眠会增加)。在任何给定时间(与其余运行时序列化),它只是执行一些算术并检查是否all - idle - locked > 0
...如果是这样,那么程序仍然可以取得进展...如果它是0,那么你肯定陷入了僵局。
您可以通过无限循环防止 goroutine 休眠来引入活锁(就像您在实验中所做的那样,显然运行时对计时器的休眠处理不一样)。在这种情况下,运行时将无法检测到死锁,并且会永远运行。
此外,我不确定运行时到底何时检查死锁 - 进一步检查谁调用了它checkdead()
如果您有兴趣,可能会在那里产生一些见解。
免责声明 - 我不是 Go 核心开发者,我只是在电视上玩过一个 :-)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)