Go语言channel缓冲与阻塞原理详解
时间:2026-10-18 07:30 作者:emer 分类: 无
前言
channel 是 Go 语言 goroutine 之间通信的核心机制,很多新手写并发程序时会遇到 goroutine 阻塞、死锁、数据写不进去等问题,根源都是没搞懂无缓冲通道和有缓冲通道的阻塞规则。本篇结合代码讲清 channel 的缓冲模型与阻塞时机。
一、无缓冲通道(unbuffered channel)
ch := make(chan int)
go func() {
ch <- 100 // 发送
}()
v := <-ch // 接收
无缓冲通道容量为 0,发送方必须等到有接收方准备好才会完成发送,属于"同步握手"。如果只发不收,发送 goroutine 会永久阻塞。
二、有缓冲通道(buffered channel)
ch := make(chan int, 3)
ch <- 1
ch <- 2
ch <- 3
// 再发第4个会阻塞,直到有人接收腾出位置
容量为 3 时,前 3 个元素先进缓冲区,发送方不会阻塞;缓冲区满了之后,发送方才会等待。接收方在缓冲区为空时阻塞。
三、阻塞与关闭的常见规则
- 向已关闭的 channel 发送数据会 panic;
- 从已关闭的 channel 接收会得到零值,ok 标识为 false;
- 关闭后再次关闭会 panic;
- 遍历 channel 用 range,channel 关闭后 range 自动退出。
四、常见踩坑
- 忘记接收导致发送 goroutine 泄漏,程序卡住;
- 缓冲容量设置过大失去解耦意义,过小又频繁阻塞;
- 主 goroutine 提前退出,子协程数据没发完就被回收。
总结
无缓冲通道做同步通信,有缓冲通道做异步削峰。理解"缓冲区满则发送阻塞、空则接收阻塞"这两条规则,就能避开大部分 channel 死锁问题。
遇到问题加QQ23979811 协助处理