Golang程序启用race标志后未返回的问题
Golang程序启用race标志后未返回的问题 各位专家好,
我正在尝试创建一个死锁错误,并使用了以下代码:
package main
import "fmt"
func main() {
channel := make(chan int)
go func(channel chan int) {
for i := 0; i < 100; i++ {
channel <- i
}
}(channel)
for val := range channel {
fmt.Println(val)
}
}
当我使用以下命令运行程序时
go run -race main.go
程序永远不会返回。但是,当我运行相同的程序而不使用 -race 标志时,它会返回一个死锁错误。
请帮我解决这个问题。
更多关于Golang程序启用race标志后未返回的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
大家好,
这真的是一个死锁吗?他只是从一个永远不会关闭的通道中读取数据,我认为这种行为既是正常的,也是符合设计预期的。
更多关于Golang程序启用race标志后未返回的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
据我所知,这是Go方面一个相当古老的问题,请参阅 runtime: program with deadlock doesn’t fail if use -race flag · Issue #20588 · golang/go · GitHub
@telo_tade 如果我说错了请纠正我。一般来说,死锁就是“等待永远不会发生的事情”。在这个例子中,消费者会等待从通道传来值,但这永远不会发生,并且没有其他 goroutine 可以执行,因此会抛出死锁错误。是这样吗?
这是一个典型的死锁检测问题。当使用 -race 标志时,Go 的竞态检测器会改变程序的调度行为,这可能导致死锁检测的时机发生变化。
在你的代码中,问题在于:
- 协程发送了 100 个值到 channel
- 主协程通过
range循环接收这些值 - 发送协程完成后,channel 没有被关闭,导致主协程在
range上永久阻塞
解决方案: 在发送完成后关闭 channel:
package main
import "fmt"
func main() {
channel := make(chan int)
go func(channel chan int) {
for i := 0; i < 100; i++ {
channel <- i
}
close(channel) // 关键:发送完成后关闭channel
}(channel)
for val := range channel {
fmt.Println(val)
}
}
或者使用带缓冲的 channel:
package main
import "fmt"
func main() {
channel := make(chan int, 100) // 使用缓冲channel
go func(channel chan int) {
for i := 0; i < 100; i++ {
channel <- i
}
}(channel)
// 等待所有值发送完成
for i := 0; i < 100; i++ {
val := <-channel
fmt.Println(val)
}
}
关于竞态检测器行为的说明:
竞态检测器 (-race) 会:
- 增加内存使用和运行时间
- 改变 goroutine 的调度时机
- 可能延迟死锁检测
在不使用 -race 时,Go 运行时能更快检测到所有 goroutine 都阻塞的情况。使用 -race 时,由于额外的同步和检查,死锁检测可能不会立即触发。
验证死锁的更好方法:
package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.Mutex
// 第一次加锁
mu.Lock()
// 尝试在同一个goroutine中再次加锁(会导致死锁)
mu.Lock() // 这里会永久阻塞
fmt.Println("这行永远不会执行")
}
这个例子在使用和不使用 -race 时都会产生死锁。

