读取和写通道超时, 是很多人在使用通道过程中经常遇到的, 下面就介绍一下通道,然后简单的对读写通道做超时处理
1. 通道采用的是FIFO(先进先出)
2. 通道的创建
chn := make(chan int, 0) // 创建读写int类型的通道, 0 代表着缓存为0,即写同时必须读取, 否则将堵塞
readOnlyChn := make(<-chan int) // 只读通道
writeOnlyChn := make(chan<- int) // 只写通道
3. 关闭通道
i. 读通道直接返回0(整数类型),bytes则返回[],
ii. 写通道 会抛出异常 (send on closed channel)
4. 判断通道是否关闭
v, ok := <-chn // ok=true说明正常,ok=false说明通道关闭
5. 通道置为nil
i. 读写通道时都会死锁
ii. select 前置 nil,则select时直接忽略,select后没有其它的case则同样堵塞
上面的使用中, 当通道被置为nil的时候虽然由于加了default不会造成死锁, 但default依然会进行不断的打印执行;
有人说了, 可以在default时判断通道是否为nil, 思路是对的,但是却没那么简单, Go中只有值传递, 即你在传通道这个参数的时候是对通道引用的拷贝, 而不是其本身, 所以通道置nil,其实recv函数内部的chn还是非空的
这样, 不管是通道为nil还是关闭通道都能够正常监控到了, 并及时退出协程了
package main import ( "fmt" "time" ) func recv(chn *chan int) { for { select { case v, ok := <-*chn: fmt.Println("value: ", v, "; ok: ", ok) if !ok { fmt.Println("channel closed!!! ") return // 退出协程 } default: if nil == *chn { fmt.Println("channel == nil"); return } fmt.Println("recv alive print.") time.Sleep(time.Second * 1) } } } func main() { var chn = make(chan int, 0) //var readOnlyChn = make(<-chan int) //var writeOnlyChn = make(chan<- int) /* 先启动接收协程, 在通道写入数据的时候进行读出, 由于之前创建了 0 缓存的通道, 写不同时读出造成堵塞 */ go recv(&chn) chn<-1024 // 写入1024数据 time.Sleep(time.Second * 2) // 延时两秒, 好让接收线程接收处理写入数据 chn = nil //close(chn) // 关闭通道 time.Sleep(5 * time.Second) }下一篇介绍context