无缓冲 channel 是同步握手,本质是没有队列、不暂存数据、强制发送与接收双方同时就绪;其行为不同于缓冲为0的 buffered channel,而是要求goroutine严格同步。

无缓冲 channel 是同步握手,不是“没缓存的 buffered channel”
无缓冲 chan int 和 chan int, 0 等价,但它的本质不是“缓冲为 0”,而是**没有队列、不暂存数据、强制双方同时到场**。发送方写 ch 会卡住,直到有 goroutine 正在执行 <code>;反过来也一样。
- 常见错误现象:用
make(chan struct{}, 0)当信号量,结果主 goroutine 先close(ch),子 goroutine 还在等接收 —— 它永远收不到,直接死锁 - 正确用法只有一种:当作协程间“你干完我才动”的协调点,比如
done := make(chan bool)配合go func() { work(); done + <code> - 别把它当轻量级任务队列用 —— 没缓冲,就不存在“排队”,只有“堵门”
有缓冲 channel 的缓冲区是固定大小的队列,不是弹性管道
make(chan string, 100) 创建的是一个最多存 100 个 string 的环形缓冲区。它不扩容、不自动清理、不感知消费速度 —— 只管“满不满”和“空不空”。
- 常见错误现象:设了
make(chan int, 10000)收日志,但忘了起 goroutine 消费,生产者不断写入,内存持续上涨,最后 OOM - 参数差异:缓冲大小必须是编译期常量或变量(如
n := 16; ch := make(chan int, n)),但创建后不可变;传负数会 panic - 性能影响:小缓冲(1–16)能平滑突发流量,几乎零开销;过大(>1024)会掩盖背压问题,让生产者盲目快跑,消费者永远追不上
关闭有缓冲 channel 后,还能读出剩余数据
关闭 ch 不等于清空 ch。只要缓冲区里还有值, 就继续返回数据;读完才开始返回零值 + <code>false。但往已关闭的 ch 再发数据会 panic。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
- 正确做法:仅由**唯一生产者**调用
close(ch);消费者用for val := range ch安全遍历,自动停在缓冲耗尽+关闭那一刻 - 反模式:多个 goroutine 同时往一个
ch写,没人协调谁关;或关闭后还试图ch —— Go 运行时直接崩溃,不给 recover 机会 - 注意:
len(ch)返回当前缓冲中元素个数,cap(ch)返回缓冲容量,两者都只对有缓冲 channel 有意义
选缓冲还是不缓冲?关键看通信意图,不是看“要不要阻塞”
别被“阻塞/不阻塞”带偏。真正该问的是:我需要双方严格步调一致,还是允许短暂脱节?
立即学习“go语言免费学习笔记(深入)”;
- 用无缓冲:事件通知(
done := make(chan struct{}))、初始化完成同步、防止竞态的临界点控制 - 用有缓冲:日志收集(
logs := make(chan string, 100))、任务分发(jobs := make(chan Task, 5))、避免主线程卡顿的异步写入 - 最容易踩的坑:混用语义 —— 比如用
make(chan bool, 1)做完成信号,结果发送成功但接收方迟迟未读,逻辑悄悄错位
缓冲区不是保险丝,它是泄洪闸;开多大,得看上游水势和下游排水能力 —— 不是拍脑袋填个数字就完事。

















