2 回答
TA贡献1794条经验 获得超8个赞
导致此事件发生的事件顺序如下:
触发 goroutine。
写入
2
频道。通道的容量现已耗尽。从通道中读取并输出结果。
写入
1
频道。从通道中读取并输出结果。
导致死锁的事件顺序如下:
触发 goroutine。
写入
1
频道。通道的容量现已耗尽。写入
2
频道。由于通道的缓冲区已满,因此阻塞。
您提供的输出似乎表明goroutine首先完成并且程序没有死锁,这与上述两种情况的解释相矛盾。这是发生的事情:
触发 goroutine。
写入
2
频道。2
从频道读取。写入
1
频道。输出
In f()
。输出
2
从通道接收到的数据。1
从频道读取。输出
1
从通道接收到的数据。
请记住,除非您以编程方式强制执行它们,否则您对 goroutine 的调度没有任何保证。当您启动一个 goroutine 时,该 goroutine 的第一个代码实际执行的时间以及在此之前启动代码的进度是未定义的。请注意,由于您的代码依赖于特定的事件顺序,因此它被该定义破坏,只是明确地说。
此外,在程序中的任何时候,调度程序都可以决定在不同的 goroutine 之间切换。甚至单行也fmt.Printtln(<-c)
包含多个步骤,并且在每个步骤之间都可能发生切换。
TA贡献1877条经验 获得超6个赞
要重现块,您必须多次运行该代码,这是最简单的测试方法。你没有运气的障碍。但不能保证:
var c = make(chan int, 1)
func f() {
c <- 1
fmt.Println("In f()")
}
func TestF(t *testing.T) {
go f()
c <- 2
fmt.Println(<-c)
fmt.Println(<-c)
}
并使用命令运行:
go test -race -count=1000 -run=TestF -timeout=4s
测试次数在哪里count。它再现了对我的阻塞。提供超时以不等待默认 10 分钟
- 2 回答
- 0 关注
- 107 浏览
添加回答
举报