不要等离职了,才知道for select时,若是通道已经关闭会怎么样?

golang面试官:for select时,若是通道已经关闭会怎么样?若是select中只有一个case呢?

问题

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

怎么答

  • 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进行读写,会怎么样?为何?
    • 当返回的okfalse时,执行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,不然将有一直阻塞的风险。

    文章推荐:

    若是你想天天学习一个知识点?