项目开发中,使用golang的channel进行线程内的消息传递,由于使用了多个channel,所以使用select case对通道进行消息监听,处理最先发生变化的channel,但是出现了一直监听不到的情况,程序总是执行到select 中的default处理块。
下面是示例代码:
预期的输出结果是:
received msg
sent msg
而实际结果是:
no msg received
no msg sent
原因分析
我们设置的是无缓存的通道ch1(没有在声明时设置通道容量),这种通道有个特点,就是只有sender和receiver都准备好了后它们的通讯(communication)才会发生(Blocking),无缓存的channel只有在receiver准备好后send才被执行。
从上述特点来看,怀疑是协程中的receiver还没准备好,导致主线程中的sender无法被case,因而输出了no msg sent。
PS:当 select 中的其他条件分支都没有准备好的时候,default
分支会被执行。
换句话说,就是协程和主线程同时运行,但是协程代码的执行速度低于主线程的代码导致。
测试方式:往主线程加个延时器
打印结果符合预期:
received msg
sent msg
上述结果确认了猜测,协程的执行速度低于主线程,因此针对协程开启的效率进行相关资料的查阅,确认了:
go新建一个goroutine需要一点时间,主线程走到select块的时候,接收消息的的goroutine一般都还没运行起来。
解决方案
根据实际情况,设置有缓存通道类型接口。
eg: