0

0

如何在Golang中实现Fan-Out/Fan-In模式 Go语言并发聚合设计

P粉602998670

P粉602998670

发布时间:2026-03-09 09:58:03

|

122人浏览过

|

来源于php中文网

原创

fan-out 通过固定数量 worker 并发处理任务,避免无节制启 goroutine 导致资源耗尽;需用带缓冲 channel 分发任务,及时关闭输入 channel,worker 用 for range 安全消费,且不在分发阶段做重试或阻塞 io。

如何在golang中实现fan-out/fan-in模式 go语言并发聚合设计

Fan-Out:怎么启动多个 goroutine 并发处理任务

Fan-Out 的核心是把一个输入源拆成多份,分发给多个 goroutine 同时干活。关键不是“开很多 goroutine”,而是控制并发数、避免资源耗尽。

常见错误是直接对每个元素起一个 goroutine:go process(item),数据量大时可能瞬间创建几千个 goroutine,触发调度压力甚至 OOM。

  • 用固定数量的 worker(比如 runtime.NumCPU() 或业务评估出的安全值),通过 channel 接收任务
  • 输入 channel 要关闭,否则 worker 无法退出;worker 内部用 for item := range inChan 安全消费
  • 别在 Fan-Out 阶段做重试或阻塞 IO —— 这会让某个 worker 卡住,拖慢整体吞吐
workers := 4
in := make(chan int, 100)
for i := 0; i < workers; i++ {
    go func() {
        for item := range in {
            result := heavyWork(item)
            out <- result // 发到输出 channel
        }
    }()
}

Fan-In:如何安全聚合多个 goroutine 的输出结果

Fan-In 就是把多个 goroutine 的输出统一收进一个 channel。难点不在“合并”,而在“何时结束”和“是否丢数据”。

典型错误是用 select 配合超时或默认分支,导致部分结果被跳过;或者用 close(out) 过早,漏掉还在路上的结果。

立即学习go语言免费学习笔记(深入)”;

Removal.AI
Removal.AI

AI移出图片背景工具

下载
  • 每个 worker 完成后单独 close 自己的输出 channel(如果用了多路 channel),但更推荐统一由主 goroutine 管理生命周期
  • sync.WaitGroup 等待所有 worker 退出,再 close 输出 channel —— 这是最稳的方式
  • 不要用 for range 直接读多个 channel,要用 reflect.Select 或更简单的:每个 worker 单独 go 写入同一 output channel,主 goroutine 只管读
var wg sync.WaitGroup
out := make(chan Result, 100)
for i := 0; i < workers; i++ {
    wg.Add(1)
    go func() {
        defer wg.Done()
        for item := range in {
            out <- process(item)
        }
    }()
}
go func() {
    wg.Wait()
    close(out)
}()

ctx.Done() 怎么嵌入 Fan-Out/Fan-In 链防止 goroutine 泄露

没有上下文取消的 Fan-Out/Fan-In,在调用方提前退出时会继续跑完所有任务,goroutine 和 channel 缓冲区都悬着不释放。

错误做法是只在入口 check ctx.Err(),但 worker 内部仍在读 channel、执行逻辑。

  • 每个 worker 启动时接收 ctx,并在循环中用 select 同时监听 ctx.Done() 和输入 channel
  • worker 内部的阻塞操作(如 http 调用、数据库查询)必须传入 ctx,否则 cancel 不生效
  • 输出 channel 写入前也要 select 判断 ctx 是否已取消,避免往已关闭的 channel 发送 panic
go func() {
    for {
        select {
        case item, ok := <-in:
            if !ok {
                return
            }
            result := doWork(ctx, item) // doWork 内部也用 ctx
            select {
            case out <- result:
            case <-ctx.Done():
                return
            }
        case <-ctx.Done():
            return
        }
    }
}()

为什么不能直接用 for-range + time.After 做超时聚合

很多人想用 time.After 包裹整个 Fan-In 阶段,比如 “等 5 秒,不管有没有收完都关 channel”。这会导致结果截断,而且掩盖了真正的瓶颈。

更糟的是,time.After 在 for-range 外层使用,会阻止 goroutine 正常退出 —— 因为 input channel 没关,worker 一直卡在 range 里。

  • 超时应该作用于单次任务(比如每个 http.Getctx.WithTimeout),而不是整条流水线
  • 如果业务真需要“最多等 N 秒拿到尽可能多结果”,就用带缓冲的 output channel + 单独的 timer goroutine close 它,但主读取逻辑仍要处理 !ok
  • 注意:用 time.After 代替 ctx.Done() 会丢失 cancel 原因(如 deadline exceeded vs canceled),调试困难

真正难的不是写对 Fan-Out/Fan-In,而是判断哪些环节该响应 cancel、哪些该完成、哪些该丢弃 —— 这取决于业务语义,不是模式本身能决定的。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

210

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

247

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

355

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

214

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

407

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

490

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

200

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

1397

2025.06.17

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

59

2026.03.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 6万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号