Golang优雅关闭channel的方法示例
前言
最近使用go开发后端服务,服务关闭需要保证channel中的数据都被读取完,理由很简单,在收到系统的中断信号后,系统需要做收尾工作,保证channel的数据都要被处理掉,然后才可以关闭系统。但实现起来没那么简单,下面来一起看看详细的介绍吧。
关于Gochannel设计和规范的批评:
- 在不能更改channel状态的情况下,没有简单普遍的方式来检查channel是否已经关闭了
- 关闭已经关闭的channel会导致panic,所以在closer(关闭者)不知道channel是否已经关闭的情况下去关闭channel是很危险的
- 发送值到已经关闭的channel会导致panic,所以如果sender(发送者)在不知道channel是否已经关闭的情况下去向channel发送值是很危险的
所以Golang内建的close方法可以关闭channel,如果往已经关闭的channel发送数据,则会报错:panic:closeofclosedchannel.
看如下代码,在一段时间内,生产者可以不断往channel写入数据,消费者进行处理,一段时间后channel关闭了,这个时候如果还有数据往channel发送,程序就会报错。
packagemain import( "fmt" "sync" "time" ) funcmain(){ jobs:=make(chanint) varwgsync.WaitGroup gofunc(){ time.Sleep(time.Second*3) close(jobs) }() gofunc(){ fori:=0;;i++{ jobs<-i fmt.Println("produce:",i) } }() wg.Add(1) gofunc(){ deferwg.Done() fori:=rangejobs{ fmt.Println("consume:",i) } }() wg.Wait() }
多运行几次出错的概率会比较大:
produce:33334 consume:33334 consume:33335 produce:33335 produce:33336 consume:33336 consume:33337 produce:33337 produce:33338 consume:33338 consume:33339 produce:33339 produce:33340 consume:33340 panic:sendonclosedchannel goroutine19[running]: panic(0x49b660,0xc042410bb0) C:/Go/src/runtime/panic.go:500+0x1af main.main.func2(0xc04203a180) C:/Users/tanteng/Go/src/examples/channel_close.go:18+0x6b createdbymain.main C:/Users/tanteng/Go/src/examples/channel_close.go:21+0xb8 exitstatus2
如何优雅关闭channel
那么在往通道发数据前如何判断通道是否关闭呢?
1._,ok:=<-jobs
此时如果channel关闭,ok值为false,如果channel没有关闭,则会漏掉一个jobs
2.使用select方式
再创建一个channel,叫做timeout,如果超时往这个channel发送true,在生产者发送数据给jobs的channel,用select监听timeout,如果超时则关闭jobs的channel.
完整代码如下:
packagemain import( "fmt" "sync" "time" ) funcmain(){ jobs:=make(chanint) timeout:=make(chanbool) varwgsync.WaitGroup gofunc(){ time.Sleep(time.Second*3) timeout<-true }() gofunc(){ fori:=0;;i++{ select{ case<-timeout: close(jobs) return default: jobs<-i fmt.Println("produce:",i) } } }() wg.Add(1) gofunc(){ deferwg.Done() fori:=rangejobs{ fmt.Println("consume:",i) } }() wg.Wait() }
这样就可以保证不会往已经关闭的channel中发送数据了。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。