使用通信顺序进程(CSP)模型的 Go 语言通道
在并发编程中,许多编程语言采用共享内存/状态模型。然而,Go 通过实现 通信顺序进程(CSP)模型来区别于众多。在CSP中,程序由不共享状态的并行进程组成;相反,它们通过通道进行通信和同步操作。因此,对于有兴趣采用Go的开发人员来说,理解通道的工作原理变得至关重要。在本文中,我将使用愉快的比喻,描述Gophers运营他们的想象中的咖啡馆,因为我坚信人类更适合通过视觉学习。
场景
Partier、Candier 和 Stringer 正在经营一家咖啡馆。鉴于制作咖啡比接受订单需要更多时间,Partier 将负责从顾客那里接受订单,然后将这些订单传递给厨房,Candier 和 Stringer 将准备咖啡。
无缓冲通道
最初,咖啡馆以最简单的方式运营:当收到新订单时,Partier 将订单放入通道中,并等待,直到 Candier 或 Stringer 中的任何一个将其取走,然后才继续接受任何新订单。Partier 和厨房之间的这种通信是通过无缓冲通道实现的,使用 ch := make(chan Order) 创建。当通道中没有待处理的订单时,即使 Stringer 和 Candier 都准备好接受新订单,他们仍然处于空闲状态,等待新订单到达。
无缓冲通道
当收到新订单时,Partier 将其放入通道中,使订单可以被 Candier 或 Stringer 之一取走。但是,在继续接受新订单之前,Partier 必须等待其中之一从通道中取回订单。
由于 Stringer 和 Candier 都可以接受新订单,所以新订单将立即被其中一个接受。然而,具体的接收者无法保证或预测。Stringer 和 Candier 之间的选择是不确定的,它取决于诸如调度和Go运行时的内部机制等因素。假设 Candier 得到了第一个订单。
在 Candier 完成处理第一个订单后,她返回等待状态。如果没有新订单到达,Candier 和 Stringer 两个工作者都将保持空闲状态,直到 Partier 再次将订单放入通道中以供处理。
当新订单到达并且 Stringer 和 Candier 都可以处理它时。即使 Candier 刚刚处理了前一个订单,接收新订单的特定工作者仍然是不确定的。在这种情况下,假设 Candier 再次被分配到了第二个订单。
到达一个新订单 order3,Candier 此时正在处理 order2,她没有在 order := <-ch 这一行等待,Stringer 成为唯一可用的工作者来接收 order3。因此,他会接收到它。
在 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。
带缓冲通道
无缓冲通道可以工作,但它限制了整体吞吐量。如果他们只接受一些订单来按顺序在后台(厨房)处理它们,那会更好。这可以通过带缓冲通道实现。现在,即使 Stringer 和 Candier 忙于处理他们的订单,只要通道不满,即可让 Partier 将新订单放入通道中,并继续接受额外的订单,例如最多3个未处理订单。
通过引入带缓冲通道,咖啡馆提高了处理更多订单的能力。然而,需要仔细选择适当的缓冲区大小,以保持顾客合理的等待时间。毕竟,没有顾客愿意忍受过长的等待时间。有时,拒绝新订单可能比接受它们并无法及时完成更为可接受。此外,在短暂的容器化(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 语言通道
在并发编程中,许多编程语言采用共享内存/状态模型。然而,Go 通过实现 通信顺序进程(CSP)模型来区别于众多。在CSP中,程序由不共享状态的并行进程组成;相反,它们通过通道进行通信和同步操作。因此…...
VPN网关
阿里云VPN网关(VPN Gateway,简称VPN)是一款基于Internet,通过加密通道将企业数据中心、办公网或终端与专有网络(VPC) 安全可靠连接起来的服务。 VPN网关提供IPsec-VPN和SSL-VPN两种。 网络连接方式应用场景IPsec-VPN支持在企业本地数据中心、企业办公网…...
产品展示视频制作的要点
制作产品展示视频时通过精心策划的视频剧本和拍摄手法,可以准确地呈现活动的目的、主题和特点,让观众更好地理解和认同活动的意义。深圳产品活动视频制作公司老友记小编还为您整理了以下一些重要的制作要点: 1.明确目标受众:了解你…...
appium+python自动化测试
获取APP的包名 1、aapt即Android Asset Packaging Tool,在SDK的build-tools目录下。该工具可以查看apk包名和launcherActivity 2、在android-sdk里面双击SDK-manager,下载buidl-tools 3、勾选build-tools,随便选一个版本,我这里选的是24的版…...
【AI辅助办公】PDF转PPT,移除水印
PDF转PPT 将PDF上传链接即可转换成PPT。 https://www.camscanner.com/pdftoppthttps://www.camscanner.com/pdftoppt移除水印 第一步:打开视图-宏 第二步:输入宏名(可以是人以文字…...
ssm农业视频实时发布管理系统源码
ssm农业视频实时发布管理系统源码108 开发工具:idea 数据库mysql5.7 数据库链接工具:navcat,小海豚等 技术: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 应用程序(Application) 1.3.2 服务器(Server) 1.4 WSGI 接口的使用示例 1.5 WSGI接口的优势 1 WSGI接口 上一节实现了静态服务器,但是当…...
Understanding Lockup Cells
工具会分析扫描链和EDT逻辑之间的控制时序元素的时钟的时序关系,当必须要同步时钟并保持数据完整性时插入边沿触发寄存器(lockup cells)。 可以使用report_edt_lockup_cells命令来展示工具已经插入的lockup cells的详细报告。 Lockup Cell Insertion 工具会分析控制时序元…...
javaCV实现java图片ocr提取文字效果
引入依赖: <dependency><groupId>org.bytedeco</groupId><artifactId>javacv-platform</artifactId><version>1.5.5</version></dependency> 引入中文语言训练数据集:chi_sim GitHub - tesseract-ocr…...
七牛云OSS存储
前言: 七牛云的存储项目的附件,需要开发一套七牛云的工具类,可以使用该工具类进行七牛云服务器进行文件的上传与下载操作; 七牛云的文档学习: 相关的依赖项的配置: <dependency><groupId>com.amazonaws</groupId><artifactId>aws-java-sdk-s3…...
11.物联网lwip,网卡原理
一。LWIP协议栈内存管理 1.LWIP内存管理方案 (1)堆heap 1.灰色为已使用内存 2.黑色为未使用内存 3.紫色为使用后内存 按照某种算法,把数据放在内存块中 (2)池pool 设置内存池,设置成大小相同的内存块。 2…...
视频监控/视频汇聚/视频云存储EasyCVR平台接入华为ivs3800平台提示400报错,该如何解决?
开源EasyDarwin视频监控TSINGSEE青犀视频平台EasyCVR能在复杂的网络环境中,将分散的各类视频资源进行统一汇聚、整合、集中管理,在视频监控播放上,视频云存储/安防监控汇聚平台可支持1、4、9、16个画面窗口播放,可同时播放多路视频…...
WordPress主题Zing V2.2.1/模块化WordPress响应式通用企业商城主题
WordPress主题Zing V2.2.1,模块化WordPress响应式通用企业商城主题。 功能介绍 百度熊掌号文章实时推送、原创保护 多设备支持自适应布局,支持电脑、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系统对于企业来说重要性不言而喻,不管是财务、生产、销售还是采购,都需要用到ERP系统来协助。…...
Vue2-replace属性、编程式路由导航、缓存路由组件、两个新的生命周期钩子、路由守卫、路由器工作模式
🥔:如果事与愿违,那一定是上天另有安排 更多Vue知识请点击——Vue.js VUE2-Day13 router-link的replace属性编程式路由导航1、什么是编程式路由导航2、如何编码3、使用案例示例说明 缓存路由组件两个新的生命周期钩子路由守卫1、路由元信息2、…...
C语言:指针的运算
一、指针 或 - 整数 指针 或 - 整数表示指针跳过几个字节(具体跳过几个字节由指针类型决定) 本文不做具体讲解,详解跳转链接: 《C语言:指针类型的意义》 二、指针 - 指针 前提条件:指针类型相同并且指向同…...
设计模式的使用——模板方法模式+动态代理模式
一、需求介绍 现有自己写的的一套审批流程逻辑,由于代码重构,需要把以前的很多业务加上审批的功能,再执行完审批与原有业务之后,生成一个任务,然后再统一处理一个任务(本来是通过数据库作业去处理的&#x…...
C++学习记录——삼십 智能指针
文章目录 1、为什么需要智能指针?2、内存泄漏3、智能指针的使用及原理1、RAII思想2、拷贝问题1、unique_ptr2、shared_ptr1、多线程2、循环引用3、定制删除器 1、为什么需要智能指针? 看一个场景 int div() {int a, b;cin >> a >> b;if (b…...
插件式架构 与 ReSharper、Visual Studio的故事
文章首发地址 ReSharper和Visual Studio的故事 ReSharper是一款由JetBrains公司开发的Visual Studio插件,它主要用于提高Visual Studio的开发效率和改善代码质量。ReSharper在早期的版本中被称为"Omea Code",它最初是JetBrains一个研究项目的…...
C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...
windows系统MySQL安装文档
概览:本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容,为学习者提供全面的操作指导。关键要点包括: 解压 :下载完成后解压压缩包,得到MySQL 8.…...
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
以Module Federation 插件详为例,Webpack.config.js它可能的配置和含义如下: 前言 Module Federation 的Webpack.config.js核心配置包括: name filename(定义应用标识) remotes(引用远程模块࿰…...
自然语言处理——文本分类
文本分类 传统机器学习方法文本表示向量空间模型 特征选择文档频率互信息信息增益(IG) 分类器设计贝叶斯理论:线性判别函数 文本分类性能评估P-R曲线ROC曲线 将文本文档或句子分类为预定义的类或类别, 有单标签多类别文本分类和多…...
Vue3中的computer和watch
computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...
深入理解 React 样式方案
React 的样式方案较多,在应用开发初期,开发者需要根据项目业务具体情况选择对应样式方案。React 样式方案主要有: 1. 内联样式 2. module css 3. css in js 4. tailwind css 这些方案中,均有各自的优势和缺点。 1. 方案优劣势 1. 内联样式: 简单直观,适合动态样式和…...
