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中发送数据了。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。