当前位置: 首页 > news >正文

使用通信顺序进程(CSP)模型的 Go 语言通道

在并发编程中,许多编程语言采用共享内存/状态模型。然而,Go 通过实现 通信顺序进程(CSP)模型来区别于众多。在CSP中,程序由不共享状态的并行进程组成;相反,它们通过通道进行通信和同步操作。因此,对于有兴趣采用Go的开发人员来说,理解通道的工作原理变得至关重要。在本文中,我将使用愉快的比喻,描述Gophers运营他们的想象中的咖啡馆,因为我坚信人类更适合通过视觉学习。

场景

Partier、Candier 和 Stringer 正在经营一家咖啡馆。鉴于制作咖啡比接受订单需要更多时间,Partier 将负责从顾客那里接受订单,然后将这些订单传递给厨房,Candier 和 Stringer 将准备咖啡。

011465bd7bd2d53ab38812c98ace599b.png

无缓冲通道

最初,咖啡馆以最简单的方式运营:当收到新订单时,Partier 将订单放入通道中,并等待,直到 Candier 或 Stringer 中的任何一个将其取走,然后才继续接受任何新订单。Partier 和厨房之间的这种通信是通过无缓冲通道实现的,使用 ch := make(chan Order) 创建。当通道中没有待处理的订单时,即使 Stringer 和 Candier 都准备好接受新订单,他们仍然处于空闲状态,等待新订单到达。

7221ab876b327e9d858f1387f3200fd2.png

无缓冲通道

当收到新订单时,Partier 将其放入通道中,使订单可以被 Candier 或 Stringer 之一取走。但是,在继续接受新订单之前,Partier 必须等待其中之一从通道中取回订单。

715040732a52945761ff310d468b4ed1.png

由于 Stringer 和 Candier 都可以接受新订单,所以新订单将立即被其中一个接受。然而,具体的接收者无法保证或预测。Stringer 和 Candier 之间的选择是不确定的,它取决于诸如调度和Go运行时的内部机制等因素。假设 Candier 得到了第一个订单。

a9f9fa268d0cc10377aec091013be776.png

在 Candier 完成处理第一个订单后,她返回等待状态。如果没有新订单到达,Candier 和 Stringer 两个工作者都将保持空闲状态,直到 Partier 再次将订单放入通道中以供处理。

d82446bb2d56589d2bd2b8ca402609bf.png

当新订单到达并且 Stringer 和 Candier 都可以处理它时。即使 Candier 刚刚处理了前一个订单,接收新订单的特定工作者仍然是不确定的。在这种情况下,假设 Candier 再次被分配到了第二个订单。

ed49c996a3e42661c036caa009451114.png

到达一个新订单 order3,Candier 此时正在处理 order2,她没有在 order := <-ch 这一行等待,Stringer 成为唯一可用的工作者来接收 order3。因此,他会接收到它。

1fda92f75f4155599e1d68536a3a8dd2.png

在 order3 发送给 Stringer 后不久,order4 到达。此时,Stringer 和 Candier 已经忙于处理各自的订单,没有人可以接收 order4。由于通道未缓冲,将 order4 放入通道会阻塞 Partier,直到 Stringer 或 Candier 中的任何一个变为可用以接收 order4。这种情况需要特别注意,因为我经常看到人们对于无缓冲通道(使用 make(chan order) 或 make(chan order, 0) 创建)

和带有缓冲大小为1的通道(使用 make(chan order, 1) 创建)产生困惑。因此,他们错误地预期 ch <- order4 会立即完成,使 Partier 在被阻塞之前接受 order5。如果您也是这样认为的,我已经在Go Playground上创建了一个代码片段,以帮助您纠正这种误解:https://go.dev/play/p/shRNiDDJYB4。

44cd09c341c94d75a1a14a96b572c7a2.png

带缓冲通道

无缓冲通道可以工作,但它限制了整体吞吐量。如果他们只接受一些订单来按顺序在后台(厨房)处理它们,那会更好。这可以通过带缓冲通道实现。现在,即使 Stringer 和 Candier 忙于处理他们的订单,只要通道不满,即可让 Partier 将新订单放入通道中,并继续接受额外的订单,例如最多3个未处理订单。

742e9ec62cf1d12d32ce2aa78c0e5684.png

通过引入带缓冲通道,咖啡馆提高了处理更多订单的能力。然而,需要仔细选择适当的缓冲区大小,以保持顾客合理的等待时间。毕竟,没有顾客愿意忍受过长的等待时间。有时,拒绝新订单可能比接受它们并无法及时完成更为可接受。此外,在短暂的容器化(Docker)应用程序中使用带缓冲通道时,需要谨慎,因为预计会随机重新启动,这种情况下从通道中恢复消息可能是一项具有挑战性甚至几乎不可能的任务。

通道 vs 阻塞队列

尽管本质上不同,Java 中的阻塞队列用于线程之间的通信,而 Go 中的通道用于 Goroutine 之间的通信,但阻塞队列和通道在某种程度上相似。如果您熟悉阻塞队列,理解通道肯定会很容易。

常见用途

通道是Go应用程序的一个基本且广泛使用的特性,具有多种用途。通道的一些常见用途包括:

Goroutine 通信:通道允许不同的 Goroutine 之间交换消息,使它们能够协作而无需直接共享状态。•工作池:如上所示的示例,通道通常用于管理工作池,其中多个相同的工作者从共享通道中处理传入的任务。•扇出、扇入:通道促进扇出、扇入模式,其中多个 Goroutine(扇出)执行工作并将结果发送到单个通道,另一个 Goroutine(扇入)消耗这些结果。•超时和截止日期:结合 select 语句,通道可以用于处理超时和截止日期,确保程序能够优雅地处理延迟并避免无限等待。

我将在其他文章中更详细地介绍通道的不同用途。但是,现在让我们通过实现上述提到的咖啡馆场景来结束这篇介绍性的博客,观察 Partier、Candier 和 Stringer 之间的互动,以及如何通过通道在它们之间实现顺畅的通信和协调,从而在咖啡馆中实现高效的订单处理和同步。

代码示例

package mainimport ("fmt""log""math/rand""sync""time"
)func main() {ch := make(chan order, 3)wg := &sync.WaitGroup{} // 更多关于 WaitGroup 的内容以后再介绍wg.Add(2)go func() {defer wg.Done()worker("Candier", ch)}()go func() {defer wg.Done()worker("Stringer", ch)}()for i := 0; i < 10; i++ {waitForOrders()o := order(i)log.Printf("Partier: I %v, I will pass it to the channel\n", o)ch <- o}log.Println("No more orders, closing the channel to signify workers to stop")close(ch)log.Println("Wait for workers to gracefully stop")wg.Wait()log.Println("All done")
}func waitForOrders() {processingTime := time.Duration(rand.Intn(2)) * time.Secondtime.Sleep(processingTime)
}func worker(name string, ch <-chan order) {for o := range ch {log.Printf("%s: I got %v, I will process it\n", name, o)processOrder(o)log.Printf("%s: I completed %v, I'm ready to take a new order\n", name, o)}log.Printf("%s: I'm done\n", name)
}func processOrder(_ order) {processingTime := time.Duration(2+rand.Intn(2)) * time.Secondtime.Sleep(processingTime)
}type order intfunc (o order) String() string {return fmt.Sprintf("order-%02d", o)
}

您可以复制此代码,在您的IDE上进行微调并运行,以更好地理解通道的工作方式。

相关文章:

使用通信顺序进程(CSP)模型的 Go 语言通道

在并发编程中&#xff0c;许多编程语言采用共享内存/状态模型。然而&#xff0c;Go 通过实现 通信顺序进程&#xff08;CSP&#xff09;模型来区别于众多。在CSP中&#xff0c;程序由不共享状态的并行进程组成&#xff1b;相反&#xff0c;它们通过通道进行通信和同步操作。因此…...

VPN网关

阿里云VPN网关(VPN Gateway&#xff0c;简称VPN)是一款基于Internet&#xff0c;通过加密通道将企业数据中心、办公网或终端与专有网络(VPC) 安全可靠连接起来的服务。 VPN网关提供IPsec-VPN和SSL-VPN两种。 网络连接方式应用场景IPsec-VPN支持在企业本地数据中心、企业办公网…...

产品展示视频制作的要点

制作产品展示视频时通过精心策划的视频剧本和拍摄手法&#xff0c;可以准确地呈现活动的目的、主题和特点&#xff0c;让观众更好地理解和认同活动的意义。深圳产品活动视频制作公司老友记小编还为您整理了以下一些重要的制作要点&#xff1a; 1.明确目标受众&#xff1a;了解你…...

appium+python自动化测试

获取APP的包名 1、aapt即Android Asset Packaging Tool&#xff0c;在SDK的build-tools目录下。该工具可以查看apk包名和launcherActivity 2、在android-sdk里面双击SDK-manager,下载buidl-tools 3、勾选build-tools&#xff0c;随便选一个版本&#xff0c;我这里选的是24的版…...

【AI辅助办公】PDF转PPT,移除水印

PDF转PPT 将PDF上传链接即可转换成PPT。​​​​​​ ​​​​​​​ https://www.camscanner.com/pdftoppthttps://www.camscanner.com/pdftoppt​​​​​​​​​​​​​​移除水印 第一步&#xff1a;打开视图-宏 第二步&#xff1a;输入宏名&#xff08;可以是人以文字…...

ssm农业视频实时发布管理系统源码

ssm农业视频实时发布管理系统源码108 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm package com.controller;import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; impo…...

【100天精通python】Day48:python Web开发_WSGI接口与使用

目录 1 WSGI接口 1.1 CGI 简介 1.2 WSGI 简介 1.3 定义 WSGI 接口 1.3.1 应用程序&#xff08;Application&#xff09; 1.3.2 服务器&#xff08;Server&#xff09; 1.4 WSGI 接口的使用示例 1.5 WSGI接口的优势 1 WSGI接口 上一节实现了静态服务器&#xff0c;但是当…...

Understanding Lockup Cells

工具会分析扫描链和EDT逻辑之间的控制时序元素的时钟的时序关系,当必须要同步时钟并保持数据完整性时插入边沿触发寄存器(lockup cells)。 可以使用report_edt_lockup_cells命令来展示工具已经插入的lockup cells的详细报告。 Lockup Cell Insertion 工具会分析控制时序元…...

javaCV实现java图片ocr提取文字效果

引入依赖&#xff1a; <dependency><groupId>org.bytedeco</groupId><artifactId>javacv-platform</artifactId><version>1.5.5</version></dependency> 引入中文语言训练数据集&#xff1a;chi_sim GitHub - tesseract-ocr…...

七牛云OSS存储

前言: 七牛云的存储项目的附件,需要开发一套七牛云的工具类,可以使用该工具类进行七牛云服务器进行文件的上传与下载操作; 七牛云的文档学习: 相关的依赖项的配置: <dependency><groupId>com.amazonaws</groupId><artifactId>aws-java-sdk-s3…...

11.物联网lwip,网卡原理

一。LWIP协议栈内存管理 1.LWIP内存管理方案 &#xff08;1&#xff09;堆heap 1.灰色为已使用内存 2.黑色为未使用内存 3.紫色为使用后内存 按照某种算法&#xff0c;把数据放在内存块中 &#xff08;2&#xff09;池pool 设置内存池&#xff0c;设置成大小相同的内存块。 2…...

视频监控/视频汇聚/视频云存储EasyCVR平台接入华为ivs3800平台提示400报错,该如何解决?

开源EasyDarwin视频监控TSINGSEE青犀视频平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;在视频监控播放上&#xff0c;视频云存储/安防监控汇聚平台可支持1、4、9、16个画面窗口播放&#xff0c;可同时播放多路视频…...

WordPress主题Zing V2.2.1/模块化WordPress响应式通用企业商城主题

WordPress主题Zing V2.2.1&#xff0c;模块化WordPress响应式通用企业商城主题。 功能介绍 百度熊掌号文章实时推送、原创保护 多设备支持自适应布局&#xff0c;支持电脑、Pad、手机以及各种浏览器 SEO优化首页、文章、页面、分类均支持自定义标题、关键字和描述 速度优化…...

【无需公网IP】在树莓派上搭建Web站点

目录 1.概述 2.使用 Raspberry Pi Imager 安装 Raspberry Pi OS 3.设置 Apache Web 服务器 3.1测试 web 站点 3.2安装静态样例站点 3.3将web站点发布到公网 3.4安装 Cpolar 3.5cpolar进行token认证 3.6生成cpolar随机域名网址 3.7生成cpolar二级子域名 3.8将参数保存…...

出差在外,远程访问企业局域网象过河ERP系统「内网穿透」

文章目录 概述1.查看象过河服务端端口2.内网穿透3. 异地公网连接4. 固定公网地址4.1 保留一个固定TCP地址4.2 配置固定TCP地址 5. 使用固定地址连接 概述 ERP系统对于企业来说重要性不言而喻&#xff0c;不管是财务、生产、销售还是采购&#xff0c;都需要用到ERP系统来协助。…...

Vue2-replace属性、编程式路由导航、缓存路由组件、两个新的生命周期钩子、路由守卫、路由器工作模式

&#x1f954;&#xff1a;如果事与愿违&#xff0c;那一定是上天另有安排 更多Vue知识请点击——Vue.js VUE2-Day13 router-link的replace属性编程式路由导航1、什么是编程式路由导航2、如何编码3、使用案例示例说明 缓存路由组件两个新的生命周期钩子路由守卫1、路由元信息2、…...

C语言:指针的运算

一、指针 或 - 整数 指针 或 - 整数表示指针跳过几个字节&#xff08;具体跳过几个字节由指针类型决定&#xff09; 本文不做具体讲解&#xff0c;详解跳转链接&#xff1a; 《C语言&#xff1a;指针类型的意义》 二、指针 - 指针 前提条件&#xff1a;指针类型相同并且指向同…...

设计模式的使用——模板方法模式+动态代理模式

一、需求介绍 现有自己写的的一套审批流程逻辑&#xff0c;由于代码重构&#xff0c;需要把以前的很多业务加上审批的功能&#xff0c;再执行完审批与原有业务之后&#xff0c;生成一个任务&#xff0c;然后再统一处理一个任务&#xff08;本来是通过数据库作业去处理的&#x…...

C++学习记录——삼십 智能指针

文章目录 1、为什么需要智能指针&#xff1f;2、内存泄漏3、智能指针的使用及原理1、RAII思想2、拷贝问题1、unique_ptr2、shared_ptr1、多线程2、循环引用3、定制删除器 1、为什么需要智能指针&#xff1f; 看一个场景 int div() {int a, b;cin >> a >> b;if (b…...

插件式架构 与 ReSharper、Visual Studio的故事

文章首发地址 ReSharper和Visual Studio的故事 ReSharper是一款由JetBrains公司开发的Visual Studio插件&#xff0c;它主要用于提高Visual Studio的开发效率和改善代码质量。ReSharper在早期的版本中被称为"Omea Code"&#xff0c;它最初是JetBrains一个研究项目的…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

AI病理诊断七剑下天山,医疗未来触手可及

一、病理诊断困局&#xff1a;刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断"&#xff0c;医生需通过显微镜观察组织切片&#xff0c;在细胞迷宫中捕捉癌变信号。某省病理质控报告显示&#xff0c;基层医院误诊率达12%-15%&#xff0c;专家会诊…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式

今天是关于AI如何在教学中增强学生的学习体验&#xff0c;我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育&#xff0c;这并非炒作&#xff0c;而是已经发生的巨大变革。教育机构和教育者不能忽视它&#xff0c;试图简单地禁止学生使…...

jmeter聚合报告中参数详解

sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample&#xff08;样本数&#xff09; 表示测试中发送的请求数量&#xff0c;即测试执行了多少次请求。 单位&#xff0c;以个或者次数表示。 示例&#xff1a;…...