for select时,如果通道已经关闭会怎样?select中只有一个case呢

ilikevc
发布于 2022-12-6 11:14
浏览
0收藏

问题

​for​​​循环​​select​​​时,如果通道已经关闭会怎么样?如果​​select​​​中的​​case​​只有一个,又会怎么样?

怎么答

  • for循环​​select​​时,如果其中一个case通道已经关闭,则每次都会执行到这个case。
  • 如果select里边只有一个case,而这个case被关闭了,则会出现死循环。

解释

1.for循环里被关闭的通道

for select时,如果通道已经关闭会怎样?select中只有一个case呢-鸿蒙开发者社区

for select时,如果通道已经关闭会怎样?select中只有一个case呢-鸿蒙开发者社区

  • ​c通道​​​是一个缓冲为​​0​​​的通道,在​​main​​​开始时,启动一个协程对​​c通道​​​写入​​10​​,然后就关闭掉这个通道。
  • 在​​main​​​中通过​​x, ok := <-c​​​ 接受​​通道c​​​里的值,从输出结果里看出,确实从通道里读出了之前塞入通道的​​10​​,但是在通道关闭后,这个通道一直能读出内容。

2.怎么样才能不读关闭后通道

for select时,如果通道已经关闭会怎样?select中只有一个case呢-鸿蒙开发者社区

  • ​x, ok := <-c​​​ 返回的值里第一个x是通道内的值,​​ok​​​是指通道是否关闭,当通道被关闭后,​​ok​​​则返回​​false​​​,因此可以根据这个进行操作。读一个已经关闭的通道为什么会出现false,可以看我之前的​​对已经关闭的的chan进行读写,会怎么样?为什么?​​ 。
  • 当返回的​​ok​​​为​​false​​​时,执行​​c = nil​​​ 将通道置为​​nil​​​,相当于读一个未初始化的通道,则会一直阻塞。至于为什么读一个未初始化的通道会出现阻塞,可以看我的另一篇​​对未初始化的的chan进行读写,会怎么样?为什么?​​​ 。​​select​​​中如果任意某个通道有值可读时,它就会被执行,其他被忽略。则​​select​​​会跳过这个阻塞​​case​​,可以解决不断读已关闭通道的问题。

3.如果select里只有一个已经关闭的case,会怎么样?

for select时,如果通道已经关闭会怎样?select中只有一个case呢-鸿蒙开发者社区

  • 可以看出只有一个​​case​​​的情况下,则会​​死循环​​。
  • 那如果像上面一个​​case​​​那样,把通道置为​​nil​​就能解决问题了吗?

4.select里只有一个已经关闭的case,置为nil,会怎么样?

for select时,如果通道已经关闭会怎样?select中只有一个case呢-鸿蒙开发者社区

  • 第一次读取​​case​​​能读到通道里的​​10​
  • 第二次读取​​case​​​能读到通道已经关闭的信息。此时将通道置为​​nil​
  • 第三次读取​​case​​​时main协程会被阻塞,此时整个进程没有其他活动的协程了,进程​​deadlock​

总结

  • ​select​​中如果任意某个通道有值可读时,它就会被执行,其他被忽略。
  • 如果没有​​default​​​字句,​​select​​​将有可能阻塞,直到某个通道有值可以运行,所以​​select​​​里最好有一个​​default​​,否则将有一直阻塞的风险。



文章转载自公众号:小白debug 

分类
已于2022-12-6 11:14:41修改
收藏
回复
举报
回复
    相关推荐