Go语言如何判断通道无新值写入?死锁原因解析
Go通道死锁的判断逻辑疑问
问题场景
第一段代码及运行现象
import ( "fmt" "time" ) func producer(n int) <-chan int { c := make(chan int) go func() { for i := 1; i <= n; i++ { time.Sleep(time.Second * 1) c <- i } }() return c } func consumer(r <-chan int) { for { val := <-r fmt.Println(val) } } func main() { r := producer(5) consumer(r) }
运行后会依次打印1、2、3、4、5,随后程序进入死锁状态(生产者循环结束停止生产后)。
第二段修改后的生产者代码及运行现象
修改后的producer函数如下:
func producer(n int) <-chan int { c := make(chan int) go func() { for i := 1; i <= n; i++ { time.Sleep(time.Second * 1) c <- i } time.Sleep(time.Second * 10) c <- 6 }() return c }
搭配原有的consumer和main函数运行时,程序会先打印1-5,休眠10秒后打印6,随后再次进入死锁状态。
核心疑问
消费者阻塞在读取通道时,Go语言是如何判断通道不会再有新值写入的?是否因为生产者的匿名函数执行完毕返回?
解答
Go语言的死锁检测逻辑并非提前预判“通道不会再有新值写入”,而是当所有goroutine都处于阻塞状态、没有任何可推进程序的操作时,运行时才会判定为死锁并触发panic。
针对你的代码场景:
- 在第一段代码中,生产者的匿名goroutine完成循环写入后会直接退出,此时程序中只剩下
maingoroutine(正在执行consumer函数),它阻塞在val := <-r的通道读取操作上。此时没有任何活跃的goroutine能够对该通道执行写入操作,所有goroutine都陷入阻塞,运行时检测到这个状态就会触发死锁。 - 第二段代码中,生产者goroutine在写入6后同样会退出,之后程序依然只有
consumer所在的goroutine阻塞在通道读取上,没有其他goroutine能向通道写入数据,因此再次触发死锁。
简单总结:死锁的判定依据是所有goroutine都无法继续执行,而不是提前知晓通道后续是否会有数据写入。
内容的提问来源于stack exchange,提问作者coderelliot
相关产品推荐
相关产品推荐

