栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Go语言

如何判断channel是否已经关闭

Go语言 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

如何判断channel是否已经关闭

如何判断channel是否已经关闭? 前言

好吧昨天面试腾讯挂了,其中有个问题是 “往一个已经关闭的channel写会怎样?(会panic)那怎么保证你写入的时候channel没有被关闭呢?换句话说就是怎么判断你的channel是否已经关闭?”

go为什么没有判断channel已经close的接口?

相信大家应该都遇到过 “send on closed channel” 的 panic 。这个 panic 是当你想往一个已经 close 的 channel 里面写值的时候触发。那么你当你第一次遇到这个问题是否想过 channel 是否能提供一个接口方法来判断是否已经 close 了?但是channel的源码中并没有针对是否close判断

思考方法一:通过写channel 实现
ch := make(chan int)
	go func() {
		defer func() {
			if recover() != nil {
				// close(ch) panic occur
			}
	}()
	ch <- 1
}()

直接捕获panic来判断已经关闭?这路子也太野了哈哈,不符合咱们程序员优雅的气质,咱们再思考别的

思考方式二:通过读channel 实现

用 select 和 <-ch 来结合可以解决这个问题
ok的结果和含义:
true:读到数据,并且通道没有关闭。
false:通道关闭,无数据读到。

ch := make(chan int, 10)
	go func() {
		for i:=1;i<10;i++{
			ch <- i
		}
	}()
	time.Sleep(1*time.Second)
	close(ch)
	for i:=0;i<10;i++{
		select {
		case v, ok := <- ch:
			if ok {
				fmt.Println(v)
			}else{
				fmt.Println("关掉了")
			}
		default:
			fmt.Println("没啥事")
	}
}

需要注意:
1.case 的代码必须是 _, ok:= <- ch 的形式,如果仅仅是 <- ch 来判断,是错的逻辑,因为主要通过 ok的值来判断;
2.select 必须要有 default 分支,否则会阻塞函数,我们要保证一定能正常返回;

思考方式三:通过context。官方推荐通过 context 来配合使用,我们可以通过一个 ctx 变量来指明 close 事件,而不是直接去判断 channel 的一个状态
select {
case <-ctx.Done():
    // ... exit
    return
case v, ok := <-c:
    // do something....
default:
    // do default ....
}

当ctx.Done()中有值时,则判断channel已经退出。
但需要注意!!!select 的 case 一定要先判断 ctx.Done() 事件,否则很有可能先执行了 chan 的操作从而导致 panic 问题;

总结

1.channel 并没有直接提供判断是否 close 的接口,官方推荐使用 context 和 select 语法配合使用,事件通知的方式,达到优雅判断 channel 关闭的效果;
2.channel 关闭姿势也有讲究,永远不要尝试在读端关闭,永远保持一个关闭入口处,使用 sync.WaitGroup 和 context 实现事件同步,达到优雅关闭效果;

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/990716.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号