go channel是协程间通信与同步的核心原语,兼具通信、同步、限流和信号传递能力;关键在理解其阻塞行为、关闭语义及与select配合方式。

Go 语言的 channel 是协程(goroutine)间通信与同步的核心机制,不是简单的队列,而是兼具通信、同步、限流和信号传递能力的语言原语。用好 channel,关键在于理解其阻塞行为、关闭语义和与 select 的配合方式。
channel 的阻塞特性决定通信节奏
无缓冲 channel 在发送和接收时都会阻塞,直到配对操作出现——这天然构成 goroutine 间的同步点。比如两个 goroutine 通过一个无缓冲 channel 交换数据,发送方必须等到接收方就绪才继续执行。
- 无缓冲 channel:适合“握手式”同步,如任务分发后等待结果
- 有缓冲 channel(cap > 0):发送仅在缓冲满时阻塞,接收仅在缓冲空时阻塞;适合解耦生产与消费速率
- 缓冲大小不是性能调优第一选择,而是表达逻辑意图:1 表示“最多一个待处理”,100 表示“允许短暂积压”
关闭 channel 的正确姿势与常见误区
channel 只能由发送方关闭,且关闭后不可再发送;但接收方仍可继续接收,直到缓冲数据耗尽,之后每次接收返回零值和 false(ok == false)。
- 不要在多个 goroutine 中重复 close —— 会 panic
- 不推荐用关闭 channel 作为“通知结束”的唯一手段;更适合用 done channel + 关闭 或 单独的信号 channel
- 接收端应始终检查 ok 值:
val, ok := ,尤其在 for-range 循环中
select 配合 channel 实现非阻塞与超时控制
select 让 goroutine 能同时监听多个 channel 操作,并在任一就绪时执行对应分支。它本身是阻塞的,但结合 default 和 time.After 可实现灵活控制。
立即学习“go语言免费学习笔记(深入)”;
- 加 default 分支 → 非阻塞尝试收发:
select { case v := - 加 time.After → 设置超时:
case - 避免在 select 中重复使用同一 channel 变量(尤其在循环中),防止意外复用或 nil panic
常见模式:退出信号、扇入扇出、错误传播
实际工程中,channel 很少孤立使用,常组合成可复用的并发模式:
- 退出控制:传入只读 done chan,各 goroutine 在 select 中监听,收到信号即退出
- 扇出(fan-out):一个输入 channel → 多个 worker goroutine 同时读取(需配合 sync.WaitGroup 或 done channel 协调生命周期)
-
扇入(fan-in):多个输出 channel → 合并到一个 channel(可用 goroutine + for-range 转发,或使用
reflect.Select动态处理,但通常前者更清晰) - 错误通道:将 error 类型 channel 与主数据 channel 并行传递,避免把错误混入业务数据流










