根本原因是某个阶段的 goroutine 未正确关闭输出 channel 或消费者提前退出,导致上游因同步 channel 的阻塞特性而卡住。

用 chan 拼接多个处理阶段时,为什么数据卡在中间不往下走?
根本原因通常是某个 stage 的 goroutine 没有正确关闭 out channel,或消费者提前退出导致上游阻塞。Go 的 channel 默认是同步的,send 会等 recv 准备好——如果下游没读、也没关 channel,上游就永远卡在 out 。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 每个 stage 都要确保:输入 channel 关闭后,自己处理完剩余数据,再关闭输出 channel(用
close(out)) - 用
range读 input channel,而不是手动for { select { case x, ok := ,否则容易漏掉关闭信号 - 避免在 stage 内部启动无管控的 goroutine 去写
out,这会让关闭时机不可控 - 简单示例:
func double(in <-chan int) <-chan int { out := make(chan int) go func() { defer close(out) for x := range in { out <- x * 2 } }() return out }
如何让 Pipeline 支持错误传递和提前终止?
原生 channel 不带错误语义,close() 只表示“数据结束”,不区分“正常结束”还是“出错了”。靠 panic 传播又太重,且无法跨 goroutine 捕获。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 用两个 channel 组合:
+ <code>,下游同时 select 两者 - 更常用的是封装成结构体,比如
type Result struct { Value T; Err error },统一走一个chan Result - 任意 stage 发现错误时,立即关闭自己的
out,并往 error channel 发送错误;上游收到 error 后应停止向后续 stage 发数据(需额外控制信号,如ctx.Done()) - 别依赖
recover()拦截 panic 来模拟错误流——它无法跨 goroutine 传播,且掩盖真实崩溃点
context.Context 在 Pipeline 中到底该在哪一层传?
Context 不是装饰品,它决定整个流水线的生命周期。传错位置会导致 cancel 无效、goroutine 泄露,或超时判断失准。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- Context 必须作为参数传给每个 stage 函数(如
func filter(ctx context.Context, in ),不能只在最外层创建然后内部硬编码 - 每个 stage 内部要用
select { case 主动响应取消,不能只靠读 input channel 自然退出 - 不要在 stage 内部用
context.WithTimeout(ctx, ...)覆盖父 context——这会让外部 cancel 失效;如需子超时,用context.WithDeadline并继承 parent Done - 如果某个 stage 启动了独立后台任务(如调用 HTTP API),必须把 ctx 传进去,并用
http.NewRequestWithContext()等配套方法
为什么加了 10 个 goroutine 并发 stage,性能反而更差?
不是并发越多越快。Pipeline 的瓶颈常在 channel 争用、内存分配、或 stage 间数据倾斜,盲目增加 goroutine 数只会放大调度开销和 GC 压力。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 先用
runtime.GOMAXPROCS(1)测试单核吞吐,确认单 stage 逻辑本身没锁或阻塞点(比如误用time.Sleep或同步 HTTP 调用) - channel 容量设为 0(无缓冲)适合低延迟、强顺序场景;设为小正数(如 64)可缓解短暂抖动,但别设太大——内存占用和 GC 压力会上升
- 用
pprof看goroutine数是否持续增长(泄露),或blockprofile 看 channel 阻塞时间占比 - 真正需要多 goroutine 的 stage,是 CPU 密集型(如解密、校验)或 IO 等待型(如 DB 查询);纯数据搬运(
map类操作)通常不需要
事情说清了就结束。Pipeline 最难的从来不是拼几个 chan,而是每个 stage 的边界是否清晰、关闭是否及时、错误是否可追溯——这些地方一松动,整条流水线就会在半夜三点给你发告警。










