Go 并发流水线:用 Fan-in/Fan-out 把流式数据处理做稳
test12026-10-141 次阅读
什么是 Fan-out 和 Fan-in
Fan-out 指一个数据源被多个 worker 同时消费,用来并行处理;Fan-in 指把多个 channel 的结果合并回一个 channel,方便下游统一读取。两者拼起来就是一条并发流水线:生产、并行加工、汇总。
Fan-out:一个源分发给多个 worker
下面的 gen 产生一批整数,三个 worker 各自从同一个 channel 取任务,天然负载均衡。
package main
import "fmt"
func gen(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}
func square(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- n * n
}
close(out)
}()
return out
}
func main() {
for r := range square(gen(2, 3, 4)) {
fmt.Println(r)
}
}
Fan-in:把多个 channel 合并
把 N 个相同类型的 channel 合并成一个,下游只面对一个出口。
func merge(chans ...<-chan int) <-chan int {
out := make(chan int)
var wg sync.WaitGroup
wg.Add(len(chans))
for _, c := range chans {
go func(c <-chan int) {
defer wg.Done()
for v := range c {
out <- v
}
}(c)
}
go func() {
wg.Wait()
close(out)
}()
return out
}
完整流水线:多 worker 并行加工再汇总
启动 3 个 square worker,各自处理 gen 产出的数据,最后用 merge 收口。数据量越大,并行收益越明显。
func main() {
in := gen(1, 2, 3, 4, 5, 6, 7, 8)
c1 := square(in)
c2 := square(in)
c3 := square(in)
for r := range merge(c1, c2, c3) {
fmt.Println(r)
}
}
加 context 做取消和超时
真实场景里要能随时停下整条流水线。把 context 透传进去,下游在 select 里监听 done,收到取消就退出,避免 goroutine 泄漏。
func square(ctx context.Context, in <-chan int) <-chan int {
out := make(chan int)
go func() {
defer close(out)
for {
select {
case <-ctx.Done():
return
case n, ok := <-in:
if !ok {
return
}
out <- n * n
}
}
}()
return out
}
错误处理要点
流水线里推荐用一个 error channel 单独传错误,不要在数据 channel 里塞错误值。主 goroutine 用一个 errgroup 或独立 select 收集错误,一旦致命错误就 cancel 整个 context,让所有 worker 有序退出。这样数据通道保持干净,取消逻辑也集中可控。
T
test1
文章作者
什么是 Fan-out 和 Fan-in Fan-out 指一个数据源被多个 worker 同时消费,用来并行处理;F...
- 分类
- 技术
- 发布时间
- 2026-10-14
- 字数
- 约 2105 字
- 阅读
- 1 次
