为什么这会导致Go中出现死锁?
这不是一个关于如何更好地写这篇文章的问题。这是一个关于Go为什么会在这个场景中导致死锁的问题为什么这会导致Go中出现死锁?,go,deadlock,Go,Deadlock,这不是一个关于如何更好地写这篇文章的问题。这是一个关于Go为什么会在这个场景中导致死锁的问题 package main import "fmt" func main() { chan1 := make(chan bool) chan2 := make(chan bool) go func() { for { <-chan1 fmt.Printf("chan1\n") cha
package main
import "fmt"
func main() {
chan1 := make(chan bool)
chan2 := make(chan bool)
go func() {
for {
<-chan1
fmt.Printf("chan1\n")
chan2 <- true
}
}()
go func() {
for {
<-chan2
fmt.Printf("chan2\n")
chan1 <- true
}
}()
for {
chan1 <- true
}
}
为什么这不会导致无限循环?为什么它会在放弃之前做两次完整的“ping ping”(而不是一次)
goroutine 1 [chan send]:
goroutine 5 [chan send]:
goroutine 6 [chan send]:
这说明了一切:您所有的goroutine都被阻止,试图在另一端没有人接收的频道上发送
因此,您的第一个goroutine阻塞在
chan2上,看起来很复杂,但答案很简单
它将在以下情况下死锁:
- 第一个例程正在尝试写入
chan2
- 第二个路由正在尝试写入
通道1
- Main正在尝试写入
通道1
怎么会这样?例如:
- 主写入
chan1
。在另一次写入时阻塞
- 例行程序1:
chan1
接收来自Main的数据。印刷品。写通道2上的块
- 例行程序2:
chan2
接收。印刷品。写入通道1上的块
- 例行程序1:
chan1
从例行程序2接收。印刷品。写通道2上的块
- 例行程序2:
chan2
接收。印刷品。写入通道1上的块
- 主写入
chan1
。在另一次写入时阻塞
- 例行程序1:
chan1
接收来自Main的数据。印刷品。写通道2上的块
- 主写入
chan1
。在另一次写入时阻塞
目前所有例程都被阻止。i、 e:
例行程序1无法写入通道2
,因为例行程序2未接收,但在尝试写入通道1
时实际被阻止。但是没有人在听频道1
正如@HectorJ所说,这完全取决于调度程序。但是在这种设置中,死锁是不可避免的。从运行时的角度来看,您会遇到死锁,因为所有例程都试图发送到通道,而没有例程等待接收任何内容
但为什么会这样?我会给你们讲一个故事,因为我喜欢想象我遇到僵局时的例行程序
你有两名球员(常规)和一个球(true
value)。每个球员都在等待一个球,一旦拿到球,他们就会把球传给另一个球员(通过通道)。这就是你的两个例程真正在做的事情,这确实会产生一个无限循环
问题是主循环中引入的第三个播放器。他躲在第二名球员后面,一旦他看到第一名球员双手空空,他就会向他扔另一个球。所以我们最后两个球员都拿着一个球,不能把球传给另一个球员,因为另一个球员手里已经有(第一个)球了。这个隐藏的、邪恶的球员还试图再传一个球。每个人都很困惑,因为有三个球,三个球员,没有空手
换句话说,你已经介绍了第三个打破游戏的玩家。他应该是一个裁判,在比赛开始的时候传球第一个球,看着球,但是不要再出球了!这意味着,在主例程中不应该有一个循环,而应该有一个简单的chan1,这是有帮助和有意义的。因此,我将假设频道不可能有多个附加值——这意味着Go已经将goroutine视为“休眠”,而不仅仅是被频道屏蔽。它如何/为什么处于休眠状态?它被通道操作阻塞,无法解除阻塞。运行时检测到所有goroutine都处于阻塞状态,因此不会发生任何事件来解除阻塞其中任何一个goroutine。
goroutine 1 [chan send]:
goroutine 5 [chan send]:
goroutine 6 [chan send]:
chan1
chan2
chan1
chan2
chan1
chan2
chan1
chan2
chan1
chan2
chan1
chan2
chan1
fatal error: all goroutines are asleep - deadlock!