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,可以构建高吞吐、高可扩展的数据处理系统。

相关推荐
程序员岳焱5 小时前
Java 与 MySQL 性能优化:Java 实现百万数据分批次插入的最佳实践
后端·mysql·性能优化
麦兜*6 小时前
Spring Boot启动优化7板斧(延迟初始化、组件扫描精准打击、JVM参数调优):砍掉70%启动时间的魔鬼实践
java·jvm·spring boot·后端·spring·spring cloud·系统架构
大只鹅6 小时前
解决 Spring Boot 对 Elasticsearch 字段没有小驼峰映射的问题
spring boot·后端·elasticsearch
ai小鬼头6 小时前
AIStarter如何快速部署Stable Diffusion?**新手也能轻松上手的AI绘图
前端·后端·github
IT_10247 小时前
Spring Boot项目开发实战销售管理系统——数据库设计!
java·开发语言·数据库·spring boot·后端·oracle
bobz9657 小时前
动态规划
后端
stark张宇8 小时前
VMware 虚拟机装 Linux Centos 7.9 保姆级教程(附资源包)
linux·后端
亚力山大抵8 小时前
实验六-使用PyMySQL数据存储的Flask登录系统-实验七-集成Flask-SocketIO的实时通信系统
后端·python·flask
超级小忍8 小时前
Spring Boot 中常用的工具类库及其使用示例(完整版)
spring boot·后端
CHENWENFEIc9 小时前
SpringBoot论坛系统安全测试实战报告
spring boot·后端·程序人生·spring·系统安全·安全测试