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

简介: Fan-out/Fan-in 是一种经典的并发设计模式,用于任务分发与结果聚合。Fan-out 将任务分发给多个 worker 并发执行,Fan-in 将结果汇聚统一处理。适用于数据抓取、批量计算等“多产一收”场景。通过 goroutine 和 channel,可构建高效的数据处理流水线,具备高吞吐与扩展性。使用时需注意通道设计、异常处理及取消控制等问题。

 

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


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

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

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


二、基本结构图

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

三、代码示例

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

 

目录
打赏
0
4
4
0
66
分享
相关文章
Tair分布式缓存
Redis很好用,相比memcached多了很多数据结构,支持持久化。但是在很长一段时间里,原生是不支持分布式的。后来就出现了很多redis集群类产品,Tair是其中胜出的优秀作品之一。 所以Tair的特性都是一些集群的特性,比如:容错、解决单点故障、跨机房管理、多集群管理、支持副本等。总而言之,是redis的高可用版本。
1863 1
Tair分布式缓存
Docker环境下的ROS Noetic:Ubuntu 20.04 系统下的解决方案
这就是在Docker环境下安装ROS Noetic在Ubuntu 20.04系统的一种简单方法,希望能对你有所帮助。
277 16
Go语言实战案例:实现HTTP客户端请求并解析响应
本文是 Go 网络与并发实战系列的第 2 篇,详细介绍如何使用 Go 构建 HTTP 客户端,涵盖请求发送、响应解析、错误处理、Header 与 Body 提取等流程,并通过实战代码演示如何并发请求多个 URL,适合希望掌握 Go 网络编程基础的开发者。
通义灵码 AI IDE 上线!智能体+MCP 从手动调用工具过渡到“AI 主动调度资源”
编程智能体与 MCP 的结合,不只是“工具+助手”,而是一次范式上的跃迁——从“手动调用工具”过渡到“AI 主动调度资源”。
如何判断两张图片的相似度?原来图片对比也可以如此简单!
本文介绍了图片对比技术在多个场景中的应用,如图片去重、内容审核、版权维权及相似图片搜索,并详细解析了两种主流的图片对比方法。第一种是**MD5指纹对比**,适合精确匹配完全相同的图片,具有速度快、简单易用的特点,但对稍作修改的图片无能为力。第二种是**图像哈希对比**,包括平均哈希、感知哈希等算法,能够判断图片的相似程度,适用于处理缩放、旋转或亮度调整后的图片,但在语义相似性上仍有局限。最后提到,随着机器学习和深度神经网络的发展,图片相似度判断技术将有更多可能性,值得进一步探索。
740 6
如何判断两张图片的相似度?原来图片对比也可以如此简单!
Go语言pprof 性能分析与 debug 技巧
本文深入讲解了 Go 语言中 pprof 性能分析与调试技巧,涵盖 CPU、内存、阻塞及 Goroutine 等多维度性能剖析,适用于排查性能瓶颈和服务调优。
Go语言Web开发框架实践:路由、中间件、参数校验
Gin框架以其极简风格、强大路由管理、灵活中间件机制及参数绑定校验系统著称。本文详解其核心功能:1) 路由管理,支持分组与路径参数;2) 中间件机制,实现全局与局部控制;3) 参数绑定,涵盖多种来源;4) 结构体绑定与字段校验,确保数据合法性;5) 自定义校验器扩展功能;6) 统一错误处理提升用户体验。Gin以清晰模块化、流程可控及自动化校验等优势,成为开发者的优选工具。
分布式系统架构8:分布式缓存
本文介绍了分布式缓存的理论知识及Redis集群的应用,探讨了AP与CP的区别,Redis作为AP系统具备高性能和高可用性但不保证强一致性。文章还讲解了透明多级缓存(TMC)的概念及其优缺点,并详细分析了memcached和Redis的分布式实现方案。此外,针对缓存穿透、击穿、雪崩和污染等常见问题提供了应对策略,强调了Cache Aside模式在解决数据一致性方面的作用。最后指出,面试中关于缓存的问题多围绕Redis展开,建议深入学习相关知识点。
535 8
如何安装与使用Java EE 8、Servlet 3.0及Apache Maven进行高效开发
【7月更文第1天】搭建高效Java EE 8开发环境,包括安装JDK、选择WildFly或Payara Server作为应用服务器,以及安装Apache Maven。使用Maven创建Servlet 3.0 Web项目,编写 HelloWorldServlet,打包部署到服务器,通过访问特定URL测试应用。这一流程助力开发者实现快速原型和大型项目开发。
353 0
电商ERP系统中电商API接口的应用
电商API接口在电子商务中扮演着至关重要的角色,它们允许开发者将电商功能集成到自己的应用程序中,实现商品检索、订单处理、支付、物流跟踪等功能。以下是关于电商API接口的应用:
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等