Go语言并发模型与模式:Fan-out / Fan-in 模式

在并发系统中,Fan-out / Fan-in 模式是一种经典的设计方式,用于在多个 goroutine 之间进行任务分发和结果聚合,常用于提高处理吞吐量和并发能力。


一、什么是 Fan-out / Fan-in 模式?

  • Fan-out(扇出) :将任务从一个入口分发给多个 worker 并发执行。
  • Fan-in(扇入) :将多个 worker 的结果汇聚到一个通道中进行统一处理。

这种模式适用于"多产一收"的数据处理流程,如数据抓取、批量计算等。


二、基本结构图

csharp 复制代码
     ┌────────────┐
     │ 任务生产者 │
     └────┬───────┘
          │
      Fan-out
  ┌──────┴──────┐
  ▼      ▼      ▼
Worker Worker Worker
  │      │      │
  └──────┬──────┘
       Fan-in
         │
   ┌─────▼─────┐
   │ 结果处理器 │
   └───────────┘

三、代码示例

go 复制代码
package main

import (
    "fmt"
    "math/rand"
    "sync"
    "time"
)

func producer(count int) <-chan int {
    out := make(chan int)
    go func() {
        for i := 0; i < count; i++ {
            out <- i
        }
        close(out)
    }()
    return out
}

func worker(id int, in <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        for job := range in {
            time.Sleep(time.Millisecond * time.Duration(rand.Intn(500))) // 模拟处理
            fmt.Printf("Worker %d processed job %d\n", id, job)
            out <- job * 2
        }
        close(out)
    }()
    return out
}

func merge(channels ...<-chan int) <-chan int {
    var wg sync.WaitGroup
    out := make(chan int)

    output := func(c <-chan int) {
        for val := range c {
            out <- val
        }
        wg.Done()
    }

    wg.Add(len(channels))
    for _, c := range channels {
        go output(c)
    }

    go func() {
        wg.Wait()
        close(out)
    }()
    return out
}

func main() {
    rand.Seed(time.Now().UnixNano())
    input := producer(10)

    // Fan-out:启动3个worker处理任务
    w1 := worker(1, input)
    w2 := worker(2, input)
    w3 := worker(3, input)

    // Fan-in:合并3个worker输出
    result := merge(w1, w2, w3)

    for res := range result {
        fmt.Println("结果:", res)
    }
}

四、应用场景

Fan-out / Fan-in 非常适合如下场景:

应用场景 示例
并发抓取网页 多个 URL 同时请求并聚合结果
批量图像处理 多图片缩放或加水印
数据清洗与计算 并发处理 CSV/日志数据
大量任务排队处理 多任务分发并收集结果

五、注意事项

✅ 优点:

  • • 利用多核并发,显著提高处理效率;
  • • 模块清晰,生产者-工作者-聚合器分离;
  • • 易于扩展和监控。

⚠️ 注意事项:

  • • 输入通道必须是"广播型",即可被多个 worker 消费;
  • • 合并函数 merge 要注意关闭输出通道;
  • • worker 中如有异常(如 panic)应提前恢复;
  • • 可加 context 实现取消控制;

六、小结

Fan-out / Fan-in 是构建并发处理流水线的核心模式,结合 goroutine 和 channel,可以构建高吞吐、高可扩展的数据处理系统。

相关推荐
梦想很大很大4 分钟前
使用 Go + Gin + Fx 构建工程化后端服务模板(gin-app 实践)
前端·后端·go
毅炼12 分钟前
Java 基础常见问题总结(4)
java·后端
想用offer打牌34 分钟前
MCP (Model Context Protocol) 技术理解 - 第一篇
后端·aigc·mcp
千寻girling39 分钟前
Koa.js 教程 | 一份不可多得的 Node.js 的 Web 框架 Koa.js 教程
前端·后端·面试
程序员清风1 小时前
北京回长沙了,简单谈谈感受!
java·后端·面试
何中应1 小时前
请求头设置没有生效
java·后端
NPE~1 小时前
自动化工具Drissonpage 保姆级教程(含xpath语法)
运维·后端·爬虫·自动化·网络爬虫·xpath·浏览器自动化
宋小黑2 小时前
JDK 6到25 全版本网盘合集 (Windows + Mac + Linux)
java·后端
念何架构之路2 小时前
Go进阶之panic
开发语言·后端·golang
先跑起来再说2 小时前
Git 入门到实战:一篇搞懂安装、命令、远程仓库与 IDEA 集成
ide·git·后端·elasticsearch·golang·intellij-idea