会,无缓冲channel要求收发同步,一方未就绪即阻塞goroutine;高频场景易卡死,应优先用带缓冲channel并合理设容量,配合select+default避免死锁。
会,而且影响非常直接——channel 用错地方、选错容量、阻塞模式不匹配,都会让 goroutine 大量挂起或调度失衡,性能掉得比不用 channel 还快。
无缓冲 channel(即 make(chan int))要求发送和接收必须同步完成。只要一方没准备好,goroutine 就立即阻塞,进入等待队列。
常见于日志采集、事件广播等场景,但若 sender 和 receiver 处理速度不一致(比如 receiver 因磁盘 I/O 变慢),所有 sender 都会被拖住,goroutine 数暴涨,调度器压力陡增。
channel,缓冲大小按峰值吞吐预估(如 make(chan int, 1024))channel 当“轻量消息队列”用;它本质是同步信号量,不是异步管道select + default 做非阻塞尝试,避免死等:select {
case ch <- x:
// 成功
default:
// 缓冲满或无接收者,丢弃或降级处理
}很多人以为 “用 channel 就不用锁”,结果把本该用 sync.Mutex 保护的计数器、状态机硬塞进 channel,反而引入更多 goroutine 切换和调度开销。
例如:每秒百万次计数,用 chan int 转发加法请求,比直接用 atomic.AddInt64 慢 10–50 倍,且 channel 自身有内存分配和锁(底层用 runtime.lock)。
sync/atomic 或 sync.Mutex
channel 的优势在解耦生产/消费节奏、跨 goroutine 控制流(如超时、取消、扇入扇出),不在替代基础并发原语go tool trace 查看 Proc Status 和 Goroutine Analysis,如果大量 goroutine
停留在 chan send 或 chan recv,基本就是误用了close(ch) 只能调用一次;重复关闭触发 panic: close of closed channel。向已关闭的 channel 发送数据也会 panic,但接收是安全的(返回零值+false)。
这问题常出现在多 goroutine 协同关闭的场景,比如 worker pool 中多个 goroutine 都想关同一个 done 通道。
sync.Once 包裹 close,或用 context.Context 替代select + default 配合 recover 是反模式;应靠设计规避,而非运行时兜底最隐蔽的性能陷阱不是 channel 多慢,而是它让你误以为“已经解耦了”,结果 goroutine 堆积、GC 压力上升、延迟毛刺频发——而这些在本地小压测里根本看不出来。