关于golang:不要等离职了才知道for-select时如果通道已经关闭会怎么样

8次阅读

共计 1306 个字符,预计需要花费 4 分钟才能阅读完成。

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 进行读写,会怎么样?为什么?。
    • 当返回的 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,否则将有始终阻塞的危险。

    文章举荐:

    • golang 面试题:对曾经敞开的的 chan 进行读写,会怎么样?为什么?
    • golang 面试题:对未初始化的的 chan 进行读写,会怎么样?为什么?
    • golang 面试题:​reflect(反射包)如何获取字段 tag​?为什么 json 包不能导出公有变量的 tag?
    • golang 面试题:json 包变量不加 tag 会怎么样?
    • golang 面试题:怎么防止内存逃逸?
    • golang 面试题:简略聊聊内存逃逸?
    • golang 面试题:字符串转成 byte 数组,会产生内存拷贝吗?
    • golang 面试题:翻转含有 中文、数字、英文字母 的字符串
    • golang 面试题:拷贝大切片肯定比小切片代价大吗?
    • golang 面试题:能说说 uintptr 和 unsafe.Pointer 的区别吗?
    如果你想每天学习一个知识点?

    正文完
     0