Go语言无缓冲通道发送操作引发死锁问题咨询
Go语言channel死锁问题解答
你遇到的现象完全合理,是无缓冲channel使用的典型错误场景,属于Go并发编程的常见难点之一。
死锁原因说明
Go中未指定缓冲区大小的无缓冲channel,发送操作会永久阻塞直到有其他goroutine执行对应接收操作,同理接收操作也会阻塞直到有其他goroutine发送数据。
你贴出的错误代码执行流程如下:
func main() { c := make(chan int) q := make(chan int) w := make(chan int) c <- 1 // 死锁触发点 go func() { q <- <-c}() // 上面代码阻塞时,这两个goroutine根本没有机会启动 go func() { w <- <-q}() // go func() {c <- 1}() //c <- 1 fmt.Println(<-w) }
- 代码运行到
c <- 1时,还没有启动任何其他goroutine,不存在任何逻辑会接收channel c中的数据,main goroutine直接在这里永久阻塞 - 整个程序此时只有main goroutine处于活跃阻塞状态,没有其他可运行的goroutine,触发Go runtime的死锁检测,抛出对应报错。
修改后可正常运行的逻辑
当你注释掉第5行的c <- 1,改成在启动两个goroutine之后再执行发送操作(或者把发送逻辑放到单独的goroutine中),执行流程变为:
- 先创建三个无缓冲channel
- 先启动两个后台goroutine,两个goroutine会分别进入阻塞状态,等待接收c、q的数据
- 此时执行
c <- 1,已经有后台goroutine在等待接收c的数据,发送操作不会阻塞 - 数据顺次经过c→q→w传递,最后main goroutine从w接收到数据,程序正常退出。
这类问题是Go并发开发的高频易错点,核心注意规则:无缓冲channel的收发是同步操作,必须配对出现在不同的goroutine中,不要在main goroutine中先执行无缓冲channel发送、后启动接收goroutine。
内容的提问来源于stack exchange,提问作者ebasruh
相关产品推荐
相关产品推荐

