GoLang使用Goroutine+Channel实现流水线处理,扇入扇出思想解决流水线上下游供需不平衡

article/2025/8/28 21:04:20

码字不易,转载请附原链,搬砖繁忙回复不及时见谅,技术交流请加QQ群:909211071

目的

在一些业务逻辑场景中, 我们要针对同一批数据依次进行不同的处理,并且它们之间是有先后顺序的。比如我们制造一个手机要经历三个阶段:buy(采购配件) - build(组装) - pack(打包),最终得到可以出售的手机。在这个需求场景中,就可以通过goroutine+无缓冲channel实现。

 

处理逻辑

我们把整个处理路程想象成消息队列,生产者buy生产,buy的下游build进行消费并生产,pack下游进行消费。逻辑图如下:

代码实现:

package mainimport ("fmt""sync""time"
)func buy(n int) <-chan string {out := make(chan string)go func() {defer close(out)for i := 1; i <= n; i++ {fmt.Println("proc:buy", i)out <- fmt.Sprintf("配件%d", i)}}()return out
}
func build(in <-chan string) <-chan string {out := make(chan string)go func() {defer close(out)for v := range in {fmt.Println("proc:build", v)out <- fmt.Sprintf("组装(%s)", v)}}()return out
}
func pack(in <-chan string) <-chan string {out := make(chan string)go func() {defer close(out)for v := range in {fmt.Println("proc:pack", v)out <- fmt.Sprintf("打包(%s)", v)}}()return out
}func main() {coms := buy(10)phones := build(coms)packs := pack(phones)for v := range packs {fmt.Println("result:", v)}
}

打印结果:

[why@whydeMacBook-Pro] ~/Desktop/go/test$go run main.go 
proc:buy 1
proc:buy 2
proc:build 配件1
proc:build 配件2
proc:buy 3
proc:pack 组装(配件1)
proc:pack 组装(配件2)
proc:build 配件3
result: 打包(组装(配件1))
result: 打包(组装(配件2))
proc:pack 组装(配件3)
result: 打包(组装(配件3))
proc:buy 4
proc:buy 5
proc:build 配件4
proc:build 配件5
proc:buy 6
proc:pack 组装(配件4)
proc:pack 组装(配件5)
proc:build 配件6
proc:buy 7
result: 打包(组装(配件4))
result: 打包(组装(配件5))
proc:pack 组装(配件6)
result: 打包(组装(配件6))
proc:build 配件7
proc:pack 组装(配件7)
result: 打包(组装(配件7))
proc:buy 8
proc:buy 9
proc:build 配件8
proc:build 配件9
proc:buy 10
proc:pack 组装(配件8)
proc:pack 组装(配件9)
proc:build 配件10
result: 打包(组装(配件8))
result: 打包(组装(配件9))
proc:pack 组装(配件10)
result: 打包(组装(配件10))

可以看到不同的处理流程是并行处理的,单个处理流程是顺序处理的。

 

供需不平衡

当三个流程处理效率相同时,上面当实现没有什么问题,但是假设运行了一段时间只会,build 处理能力下降,就会由于中间一个环节阻塞,托满整个执行效率,此时该如何处理呢?

可能大部分人都会想到,增加 build 流水线的工人啊!没错,就是这个思路,所以演变后的逻辑变成下面这样:

我们用 sleep 模拟 build 处理能力下降,演变后的代码如下:

package mainimport ("fmt""sync""time"
)func buy(n int) <-chan string {out := make(chan string)go func() {defer close(out)for i := 1; i <= n; i++ {fmt.Println("proc:buy", i)out <- fmt.Sprintf("配件%d", i)}}()return out
}
func build(in <-chan string) <-chan string {out := make(chan string)go func() {defer close(out)for v := range in {fmt.Println("proc:build", v)time.Sleep(time.Duration(time.Second))out <- fmt.Sprintf("组装(%s)", v)}}()return out
}
func pack(in <-chan string) <-chan string {out := make(chan string)go func() {defer close(out)for v := range in {fmt.Println("proc:pack", v)out <- fmt.Sprintf("打包(%s)", v)}}()return out
}//扇入,汇聚3个channel成一个
func merge(ins ...<-chan string) <-chan string {wg := sync.WaitGroup{}wg.Add(len(ins))out := make(chan string)//定义channel数据传递函数f := func(in <-chan string) {defer wg.Done()for v := range in {out <- v}}//按照传入channel个数并行处理for _, v := range ins {go f(v)}go func() {wg.Wait()close(out)}()return out
}func main() {coms := buy(10)//phones := build(coms)//扇入增加build效率phones1 := build(coms)phones2 := build(coms)phones3 := build(coms)phones := merge(phones1, phones2, phones3)packs := pack(phones)for v := range packs {fmt.Println("result:", v)}
}

打印结果:

[why@whydeMacBook-Pro] ~/Desktop/go/test$go run main.go 
proc:buy 1
proc:build 配件1
proc:buy 2
proc:buy 3
proc:buy 4
proc:build 配件3
proc:build 配件2
proc:build 配件4
proc:pack 组装(配件3)
proc:buy 5
proc:buy 6
proc:pack 组装(配件2)
proc:build 配件5
proc:build 配件6
result: 打包(组装(配件3))
result: 打包(组装(配件2))
proc:pack 组装(配件1)
result: 打包(组装(配件1))
proc:buy 7
proc:build 配件7
proc:pack 组装(配件6)
proc:buy 8
result: 打包(组装(配件6))
proc:build 配件8
proc:buy 9
proc:buy 10
proc:build 配件9
proc:pack 组装(配件5)
proc:pack 组装(配件4)
result: 打包(组装(配件5))
result: 打包(组装(配件4))
proc:build 配件10
proc:pack 组装(配件9)
proc:pack 组装(配件8)
result: 打包(组装(配件9))
result: 打包(组装(配件8))
proc:pack 组装(配件7)
result: 打包(组装(配件7))
proc:pack 组装(配件10)
result: 打包(组装(配件10))
[why@whydeMacBook-Pro] ~/Desktop/go/test$

通过结果我们可以看到,buy 和 pack 的处理仍是顺序的,而 build 变成了并行处理,解决了我们供需不平衡的问题。

ps:为了减少代码量,提高阅读体验,这里没有贴前后对比图,你可以自己运行对比一下二者的效率,可以很直观地感受到。

 

 

 

 


http://chatgpt.dhexx.cn/article/NPZ4qHJo.shtml

相关文章

mccabe java_面向过程及面向对象的扇入及扇出

面向过程的扇入及扇出&#xff1a; 扇入&#xff1a;是指直接调用该模块的上级模块的个数。即&#xff1a;called by个数 (在McCabe 里度量名称为Fan in) 扇出&#xff1a;该模块直接调用的下级模块的个数。即&#xff1a;calls to 个数(在McCabe 里度量名称为Fan out) 面向对象…

代码静态分析思维体操—扇入、扇出、圈复杂度

静态分析是一种检查代码的方法,无需执行程序。它提供了一种机制,可以审查代码结构、控制流和数据流,检测潜在的可移植性和可维护性问题,计算适当的软件质量测度。 其中控制流分析包括:扇入、扇出和圈复杂度。 常见流程图结构 一种常见的程序分析方法是通过生成程序的有向控…

FPGA Fanout-Fanin(扇入扇出)

在谈到多扇出问题之前&#xff0c;先了解几个相关的信息&#xff0c;也可以当成是名词解释。 扇入、扇出系数 扇入系数是指门电路允许的输入端数目。一般门电路的扇入系数为1—5&#xff0c;最多不超过8。扇出系数是指一个门的输出端所驱动同类型门的个数&#xff0c;或称负载…

关于 FPGA 内部信号扇入扇出

转自https://www.cnblogs.com/dxs959229640/p/3870189.html 关于 FPGA 内部信号扇入扇出 扇入、扇出系数 扇入系数是指门电路允许的输入端数目。一般门电路的扇入系数为1—5&#xff0c;最多不超过8。扇出系数是指一个门的输出端所驱动同类型门的个数&#xff0c;或称负载能力。…

软件工程考试选择题:模块的扇入扇出 深度宽度

ABCD A常作为总体设计工具的是HIPO图 B 顶层扇出大,中间扇出小,扇出指一个模块调用的模块数。 C组合是一种特殊形式的聚合关系 D状态图 扇入扇出 启发规则 一.改进软件结构提高模块独立性 初步结构分解或合并,降低耦合提高内聚。 二.模块规模应该适中 过大分…

静态分析—扇入、扇出、圈复杂度

静态分析是一种检查代码的方法&#xff0c;无需执行程序。它提供了一种机制&#xff0c;可以审查代码结构、控制流和数据流&#xff0c;检测潜在的可移植性和可维护性问题&#xff0c;计算适当的软件质量测度。 其中控制流分析包括&#xff1a;扇入、扇出、圈复杂度。 常见的…

Go语言并发之扇入和扇出

1、Go语言并发之扇入和扇出 编程中经常遇到扇入和扇出两个概念&#xff0c;所谓的扇入是指将多路通道聚合到一条通道中处理&#xff0c;Go 语言最简单的扇入 就是使用 select 聚合多条通道服务&#xff1b;所谓的扇出是指将一条通道发散到多条通道中处理&#xff0c;在Go语言…

DWcc2018免费下载及详细安装教程

DWcc2018下载及安装教程&#xff08;内附安装包下载链接&#xff09; 安装包下载&#xff1a; 百度网盘下载链接链接&#xff1a;https://pan.baidu.com/s/1tCkVVobfiUWSIrZuc7OOIg 提取码&#xff1a;0bb5 也可保存下方图片&#xff0c;微信扫码即可下载 安装步骤&#xff1a…

dreamweaver (dw)cc 2017

dreamweaver cc 2017是一款在目前工作中最优越的网页设计软件&#xff0c;被简称称为dw cc 2017。新版本比以往任何时候都变得更加专注、高效和快速&#xff0c;拥有和全新代码编辑器和更直观的用户界面和多种增强功能。比如对css预处理器等新工作流程的支持&#xff0c;可以提…

DW小知识

1.学习网页开发&#xff0c;首先你得知道怎么编写和构造HTML标记&#xff0c;用HTML标记传达你想要给用户展示的内容&#xff0c;比如文字、图片、音频和视频等。用HTML标记内容的目的是为了赋予网页语义&#xff0c;换句话讲就是要给你的网页赋予某些用户代理能够理解的含义。…

dwcc怎么设置html默认,Dreamweaver CC 2019如何设置界面首选项?

设置界面首选项 Dreamweaver为用户提供了对基本程序界面的广泛控制。您可以按照自己的喜好设置、安排和 定制各种面板。开始本书课程之前&#xff0c;您应该首先访问的位置之一是Dreamweaver Preferences (首选项)对话框。 利其他Adobe应用一样&#xff0c;首选项对话框提供描述…

html锚点链接dw怎么做,最新的DW中的锚点在哪

CSS布局HTML小编今天和大家分享dreamweaver cc2018的锚点跟跳转菜单在哪 DW中怎样让页面按钮链接到另一个页面的锚点 Dreamweaver里怎么制作锚点链接&#xff0c;跳到当前网页顶端&#xff1f;Dreamweaver里怎么制作锚点链接&#xff0c;效果&#xff1a;跳到当前网页的顶端&am…

创建 DW 项目

开发工具与关键技术&#xff1a; DW 作者&#xff1a;陈海涛 撰写时间&#xff1a;2021/4/27 1.首先创建一个文件夹&#xff0c;再在里面创建三个文件夹&#xff08;注意&#xff1a;不能使用 中文来命名&#xff09; 2.打开 DW&#xff0c;然后点击 CTALN 或者点击左上…

网页设计软件dw cc 2019 mac激活方法

Dreamweaver CC 2019 for mac是知名的网站和网页设计软件,简称dw,是设计师和程序员必备的网页代码编辑器,新版本的dw cc 2019 mac破解版提供了JavaScript重构功能、全新的EcmaScript 6支持,而且dw cc2019破解版与Chromium嵌入式框架的最新版本进行集成,这样用户可以轻松构…

DW CC2019软件安装破解教程(附安装包下载)

DW CC2019 64bit下载地址&#xff1a; 链接&#xff1a; https://pan.baidu.com/s/15dYmXLPvqDt2p-IepYrUdQ 密码&#xff1a;5rwp 安装中有任何问题添加QQ群&#xff1a;606940296&#xff08;备注软件出现问题&#xff09; 软件介绍 Adobe Dreamweaver CC 2019是Adobe公司…

网页设计软件dw cc2019直装版

Dreamweaver CC 2019 for mac是Web设计人员和开发人员设计必备的软件,dw 2019 mac破解版支持HTML、CSS、JavaScript等,功能十分强大,可以轻松帮助用户设计精美的网站网页,这次Dreamweaver cc 2019 mac破解版主要针对安全性增强功能、JavaScript重构、ECMAScript 6支持、Git…

DWCC2018HTML网页字体添加、更改

一般情况下&#xff0c;DWCC2018里是没有像宋体、楷体、微软雅黑之类的字体&#xff0c;我们可以将系统自带的字体添加到DWCC中 1、添加软件内没有的字体 **①打开DWCC2018→工具** ![在这里插入图片描述](https://img-blog.csdn.net/20181007163628785?watermark/2/text/aHR…

DWCC2018HTML基本网页设计技巧方法详解

目录&#xff1a; 一、文本格式化标记 ----------------------1、各类标签及描述 二、HTNL链接 ----------------------1、HTML链接语法 ----------------------2、在当前页面跳到指定位置 ----------------------3、图片链接 三、插入视频、图片、列表项、邮件链接等 --------…

dwcc2019写php,mac网页设计软件:DreamweaverCC2019(dwcc2019直装版)

dw cc 2019 Mac新增功能 dw cc 2019 Mac推出了一些令 Web 设计人员和开发人员激动无比的新增功能。 1、JavaScript 重构 作为 Web 开发人员&#xff0c;您现在可以使用 JavaScript 重构&#xff0c;利用范围感知功能智能地重命名函数和变量。只需一次单击&#xff0c;您就可以将…

DWCC2018基本网页设计注意要点、使用技巧

目录&#xff1a; 一、注意要点 -------------1、“实时视图”“设计”的选择 -------------2、调出属性框 -------------3、在浏览器中实时浏览自己的网页 二、部分使用技巧 -------------1、文本格式化标记 -------------2、网页整体属性编辑 -------------3、插入视频、列表…