You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言中关闭Channel后接收方Goroutine为何永不阻塞?

Go Channel close函数的本质解释

先给你明确结论:close函数既不会启动goroutine,也不会持续往通道发送默认值,它的作用只是给通道打上一个「不再接受新发送值」的标记,后续的接收行为是Go语言对已关闭通道的逻辑设计。

核心逻辑拆解

  • 通道关闭后,已发送到通道里的值依然可以被正常接收;当通道内所有值都被取完,后续的接收操作会立刻返回对应类型的零值,同时返回的ok标志会变成false。这不是通道在“发值”,而是Go语言规定:对已关闭且空的通道执行接收,不会阻塞,直接返回零值+false。
  • 没关闭通道时,当通道里的值被取完,再执行接收会陷入阻塞——因为Go认为可能还有发送方会往通道里塞值,主goroutine卡在select里无其他工作可做,就触发了死锁错误。

结合你的代码具体分析

修正转义符号后的正确代码如下:

import "fmt"
import "time"

func main(){
    intChan := make(chan int, 1)
    strChan := make(chan string, 1)

    intChan <- 3
    strChan <- "hello"
    fmt.Println("send")

    // 注释此处会触发致命错误:all goroutines are asleep - deadlock!
    close(intChan)
    close(strChan)

    for {
        select {
        case e, ok := <-intChan:
            time.Sleep(time.Second * 2)
            fmt.Println("The case intChan ok: ", ok)
            fmt.Println("The case intChan is selected.", e)

        case e, ok := <-strChan:
            time.Sleep(time.Second)
            fmt.Println("The case strChan ok: ", ok)
            fmt.Println("The case strChan is selected.", e)
        }
    }
}
  • 取消注释close后:通道被标记为关闭,接收完3和hello后,后续每次select都会随机选中某个case(因为两个通道的接收都不会阻塞),返回对应类型的零值(int是0,string是空字符串)和false,所以循环会一直执行下去。
  • 即使你一开始不往通道发值,直接close,接收操作同样会立刻返回零值+false,不会阻塞或报错——这依然是Go对已关闭通道的接收逻辑,和“发值”无关。

额外注意事项

  • 只有发送方应该关闭通道,接收方关闭会直接触发panic;
  • 往已关闭的通道发送值也会触发panic;
  • 可以多次从已关闭的通道接收,每次都会得到零值+false。

内容的提问来源于stack exchange,提问作者Pzhang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 06:30:30