Go语言多通道连续发送数据阻塞问题及解决咨询
问题分析与解决方案
你的问题核心在于两个关键问题:无缓冲通道的阻塞特性,以及接收端Goroutine仅执行一次就退出,最终导致后续发送操作被卡住。
为什么会出现这个问题?
- 无缓冲通道的发送阻塞:你创建的
chan1、chan2、chan3都是无缓冲通道(make(chan bool)默认无缓冲)。无缓冲通道的发送操作chan <- val会一直阻塞,直到有接收端准备好接收这个值。所以你的定时函数里,chan1 <- true会先执行,如果此时chan1的接收端已经退出(你的接收Goroutine只跑了一次select就结束了),这个发送会永久阻塞,后面的chan2、chan3发送根本没机会执行。 - 接收端只执行一次监听:你的接收Goroutine只做了一次
select就退出了,也就是说它只会尝试接收一次数据,之后就不再监听通道了。就算第一次chan1的发送成功了,下一次定时循环再发chan1时,已经没有接收端了,发送直接阻塞。
修正方案
这里提供两种常用的解决思路,你可以根据需求选择:
方案1:使用带缓冲的通道
给每个通道设置至少1个缓冲大小,这样发送操作可以立即完成,不需要等待接收端,缓冲会暂存数据,直到接收端读取。
修改通道创建代码:
var chan1 = make(chan bool, 1) var chan2 = make(chan bool, 1) var chan3 = make(chan bool, 1)
同时,修改接收端Goroutine,让它持续监听通道(如果需要一直接收数据的话):
go func() { var myVar bool for { // 持续循环监听 select { case val := <- chan1: myVar = val // 这里可以添加数据处理逻辑 // 不需要default分支的话可以去掉,这样会一直阻塞在chan1的接收上 } } }()
方案2:用独立Goroutine发送每个通道数据
如果不想用缓冲通道,可以在发送每个通道数据时,启动一个临时Goroutine来执行发送操作,这样三个发送操作是并行的,不会互相阻塞。
修改定时函数:
go func() { for { <-time.After(1* time.Minute) // 每个发送都放在独立Goroutine里,避免互相阻塞 go func() { chan1 <- true }() go func() { chan2 <- false }() go func() { chan3 <- true }() } }()
同样,接收端需要改成持续监听的循环,否则还是会出现后续没有接收端的问题:
go func() { var myVar bool for { select { case <- chan1: myVar = true default: // 如果需要处理无数据的情况,可以保留default,否则去掉 myVar = false } // 加短暂休眠避免空转占用CPU time.Sleep(100 * time.Millisecond) } }()
额外提示
- 如果你的接收端不需要持续运行,而是每次定时发送后才需要处理数据,那可以考虑让接收端和发送端同步,但这种场景下用缓冲通道更简单。
- 避免在无缓冲通道上发送数据时没有对应的接收端,这会导致永久阻塞,进而引发Goroutine泄漏。
内容的提问来源于stack exchange,提问作者wmfrancia
相关产品推荐
相关产品推荐

