Go channel是带同步语义的通信原语,发送/接收会阻塞直至配对就绪;必须用make创建,nil channel操作永久阻塞;类型区分读写方向;无缓冲channel要求收发goroutine同时就绪;关闭由发送方负责,重复关闭或接收方关闭均panic。
Go 语言的 channel 不是“用来传数据的管道”这种模糊说法就能讲清的——它本质是带同步语义的通信原语,发送和接收操作会阻塞,直到配对的另一端就绪。理解这一点,才能避开死锁、goroutine 泄漏等高频问题。
声明但未初始化的 channel 是 nil,对它做发送或接收会永久阻塞(不是 panic)。必须用 make(chan T) 或带缓冲的 make(chan T, cap) 显式创建。
chan int 和 chan(只写)或 (只读)类型不兼容,编译报错
make(chan ...),容易触发 GC 压力或泄漏 会阻塞直到接收方准备就绪
向 channel 发送值的语法是 ch 。它不是“把数据塞进去就完事”,而是同步等待接收方从同一 channel 取走该值(无缓冲),或缓冲未满(有缓冲)。
select + default 实现非阻塞发送:select {
case ch <- x:
// 成功发送
default:
// 缓冲满或无人接收,不阻塞
} 阻塞逻辑取决于 channel 状态
接收表达式 的行为分三种情况:有值可取(立刻返回)、channel 关闭且缓冲为空(返回零值+false)、channel 未关闭且空(阻塞)。
v, ok := ,其中 ok 为 false 表示 channel 已关闭且无剩余数据
v := 在 channel 关闭后仍会返回零值,但无法区分“收到零值”和“channel 关闭”,易引发逻辑错误
close(ch) 是无效操作,会 panicclose() 只表示“不再发送”,不释放 channel 内存,也不唤醒所有阻塞的接收者——它只影响后续的接收行为。
型模式:用 sync.WaitGroup 等待所有 sender 完成,再 close;receiver 用 for range ch 自动处理关闭真正难的不是语法,而是判断“谁该关 channel”“什么时候关”“要不要加超时”“是否需要 select 多路复用”。这些决策直接影响程序是否死锁、是否丢失消息、是否泄露 goroutine——它们藏在业务逻辑里,不在 ch 这一行代码中。