第4章 并发编程
4.5 channel
select
Go语言直接在语言级别支持select关键字,用于处理异步IO问题。
随机是怎么做到的?因为select的特点是只要其中一个case已经完成,程序就会继续往下执行,而不会考虑其他case的情况。
缓冲机制
channel缓冲,可以达到消息队列的效果。
//创建一个带缓冲的channel
ch := make(chan int, 1024) //缓冲区被填完之前都不会阻塞
//读取
for i := range ch {
fmt.Println("Received:", i)
}
超时机制
在之前对channel的介绍中,我们完全没有提到错误处理的问题,而这个问题显然是不能被忽略的。在并发编程的通信过程中,最需要处理的就是超时问题,即向channel写数据时发现channel已满,或者从channel试图读取数据时发现channel为空。如果不正确处理这些情况,很可能会导致整个goroutine锁死。
虽然goroutine是Go语言引入的新概念,但通信锁死问题已经存在很长时间,在之前的C/C++
开发中也存在。操作系统在提供此类系统级通信函数时也会考虑入超时场景,因此这些方法通常都会带一个独立的超时参数。超过设定的时间时,仍然没有处理完任务,则该方法会立即终止并返回对应的超时信息。超时机制本身虽然也会带来一些问题,比如在运行比较快的机器或者高速的网络上运行正常的程序,到了慢速的机器或者网络上运行就会出问题,从而出现结果不一致的现象,但从根本上来说,解决死锁问题的价值要远大于所带来的问题。
Go语言没有提供直接的超时处理机制,但我们可以利用select机制。虽然select机制不是
专为超时而设计的,却能很方便地解决超时问题。因为select的特点是只要其中一个case已经完成,程序就会继续往下执行,而不会考虑其他case的情况。
这样使用select机制可以避免永久等待的问题,因为程序会在timeout中获取到一个数据后继续执行,无论对ch的读取是否还处于等待状态,从而达成1秒超时的效果。
这种写法(实现并执行一个匿名的超时等待函数)看起来是一个小技巧,但却是在Go语言开发中避免channel通信超时的最有效方法。在实际的开发过程中,这种写法也需要被合理利用起来,从而有效地提高代码质量。