golang面试官:for select时,如果通道已经关闭会怎么样?如果select中只有一个case呢?
问题
for
循环select
时,如果通道已经关闭会怎么样?如果select
中的case
只有一个,又会怎么样?
怎么答
for循环 select
时,如果其中一个case通道已经关闭,则每次都会执行到这个case。如果select里边只有一个case,而这个case被关闭了,则会出现死循环。
解释
1.for循环里被关闭的通道
c通道
是一个缓冲为0
的通道,在main
开始时,启动一个协程对c通道
写入10
,然后就关闭掉这个通道。在 main
中通过x, ok := <-c
接受通道c
里的值,从输出结果里看出,确实从通道里读出了之前塞入通道的10
,但是在通道关闭后,这个通道一直能读出内容。
2.怎么样才能不读关闭后通道
x, ok := <-c
返回的值里第一个x是通道内的值,ok
是指通道是否关闭,当通道被关闭后,ok
则返回false
,因此可以根据这个进行操作。读一个已经关闭的通道为什么会出现false,可以看我之前的 对已经关闭的的chan进行读写,会怎么样?为什么? 。当返回的 ok
为false
时,执行c = nil
将通道置为nil
,相当于读一个未初始化的通道,则会一直阻塞。至于为什么读一个未初始化的通道会出现阻塞,可以看我的另一篇 对未初始化的的chan进行读写,会怎么样?为什么? 。select
中如果任意某个通道有值可读时,它就会被执行,其他被忽略。则select
会跳过这个阻塞case
,可以解决不断读已关闭通道的问题。
3.如果select里只有一个已经关闭的case,会怎么样?
可以看出只有一个 case
的情况下,则会死循环
。那如果像上面一个 case
那样,把通道置为nil
就能解决问题了吗?
4.select里只有一个已经关闭的case,置为nil,会怎么样?
第一次读取 case
能读到通道里的10
第二次读取 case
能读到通道已经关闭的信息。此时将通道置为nil
第三次读取 case
时main协程会被阻塞,此时整个进程没有其他活动的协程了,进程deadlock
总结
select
中如果任意某个通道有值可读时,它就会被执行,其他被忽略。如果没有 default
字句,select
将有可能阻塞,直到某个通道有值可以运行,所以select
里最好有一个default
,否则将有一直阻塞的风险。
文章推荐:
golang面试题:对已经关闭的的chan进行读写,会怎么样?为什么? golang面试题:对未初始化的的chan进行读写,会怎么样?为什么? golang 面试题:reflect(反射包)如何获取字段 tag?为什么 json 包不能导出私有变量的 tag? golang面试题:json包变量不加tag会怎么样? golang面试题:怎么避免内存逃逸? golang面试题:简单聊聊内存逃逸? golang面试题:字符串转成byte数组,会发生内存拷贝吗? golang面试题:翻转含有 中文、数字、英文字母
的字符串golang面试题:拷贝大切片一定比小切片代价大吗? golang面试题:能说说uintptr和unsafe.Pointer的区别吗?
如果你想每天学习一个知识点?
有疑问加站长微信联系(非本文作者)