以可视化方式解释 Go 并发 - 通道
在并发编程中,许多编程语言采用共享内存/状态模型。然而,Go 通过实现 通信顺序进程 (CSP) 区别于众多语言。在 CSP 中,一个程序由并行的进程组成,这些进程不共享状态,而是使用通道进行通信和同步它们的操作。因此,对于有意采用 Go 的开发人员来说,理解通道的工作原理变得至关重要。在本文中,我将使用 Gopher 运行他们的虚构咖啡馆的可爱比喻来阐述通道,因为我坚信人类更容易通过视觉学习。
情景
Partier、Candier 和 Stringer 经营一家咖啡馆。由于制作咖啡需要比接受订单更多的时间,Partier 将协助接受客户的订单,然后将这些订单传递到厨房,Candier 和 Stringer 在那里制作咖啡。
Gopher's Cafe
无缓冲通道
最初,咖啡馆以最简单的方式运营:每当收到新订单时,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 在 ch <- order5 处被阻塞之前接受 order5。如果您也是这样认为的,我已经在 Go Playground 上创建了一个代码片段,以帮助您纠正您的误解 https://go.dev/play/p/shRNiDDJYB4。
带缓冲通道
无缓冲通道是有效的,但它限制了总吞吐量。如果他们只接
受一些订单以便在后端(厨房)顺序处理它们,那将更好。这可以通过使用带缓冲通道来实现。现在,即使 Stringer 和 Candier 忙于处理他们的订单,只要通道不满,例如最多 3 个待处理订单,Partier 仍然可以将新订单放入通道并继续接受其他订单。
引入带缓冲通道后,咖啡馆增强了处理更多订单的能力。然而,选择适当的缓冲区大小以保持客户合理的等待时间非常重要。毕竟,没有客户想忍受过长的等待时间。有时,拒绝新订单可能比接受新订单但无法及时完成它们更可接受。此外,在使用带缓冲通道的瞬时容器化(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{}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并发可视化解释 - Select语句
相关文章:
以可视化方式解释 Go 并发 - 通道
在并发编程中,许多编程语言采用共享内存/状态模型。然而,Go 通过实现 通信顺序进程 (CSP) 区别于众多语言。在 CSP 中,一个程序由并行的进程组成,这些进程不共享状态,而是使用通道进行通信和同步它们的操作。因此&…...
kafka学习-生产者
目录 1、消息生产流程 2、生产者常见参数配置 3、序列化器 基本概念 自定义序列化器 4、分区器 默认分区规则 自定义分区器 5、生产者拦截器 作用 自定义拦截器 6、生产者原理解析 1、消息生产流程 2、生产者常见参数配置 3、序列化器 基本概念 在Kafka中保存的数…...
【Python】设计模式
设计模式分为三种类型,共23类。 创建型模式:单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式。结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。行为型模式:模版方法模式、命令模…...
C++ 数字
C 数字 通常,当我们需要用到数字时,我们会使用原始的数据类型,如 int、short、long、float 和 double 等等。这些用于数字的数据类型,其可能的值和数值范围,我们已经在 C 数据类型一章中讨论过。 C 定义数字 我们已…...
code阶段——gitgitlab安装
在code阶段,我们需要将不同版本的代码存储到一个仓库中,常见的版本控制工具就是SVN或者Git,这里我们采用Git作为版本控制工具,GitLab作为远程仓库。 Git安装 https://git-scm.com/(傻瓜式安装) GitLab安…...
C 风格文件输入/输出---无格式输入/输出
C 标准库的 C I/O 子集实现 C 风格流输入/输出操作。 <cstdio> 头文件提供通用文件支持并提供有窄和多字节字符输入/输出能力的函数,而 <cwchar>头文件提供有宽字符输入/输出能力的函数。 无格式输入/输出 从文件流获取字符 std::fgetc, std::getc …...
Spring-MVC的文件上传下载,及插件的使用(让项目开发更节省时间)
目录 一、概述 ( 1 ) 介绍 ( 2 ) 讲述 二、上传 三、下载 四、jrebel的使用 五、多文件上传 给我们带来什么收获 一、概述 ( 1 ) 介绍 Spring MVC的文件上传下载是指在Spring MVC框架中实现文件的上传和下载功能。文件上传是指将本地计算机上的文件上传到服务器端…...
算法 数据结构 递归冒泡算法 java冒泡算法 优化递归冒泡 数据结构(九)
使用递归算法实现冒泡: package com.nami.algorithm.study.day06;import java.util.Arrays;/*** beyond u self and trust u self.** Author: lbc* Date: 2023-09-05 15:36* email: 594599620qq.com* Description: keep coding*/ public class BubbleSort2 {// p…...
【计算机视觉 | 目标检测】目标检测常用数据集及其介绍(十五)
文章目录 一、STN PLAD (STN Power Line Assets Dataset)二、Satlas三、Street Dataset四、UAVVaste五、UDA-CH (Unsupervised Domain Adaptation on Cultural Heritage)六、USB (Universal-Scale Object Detection Benchmark)七、VEDAI (Vehicle Detection in Aerial Imagery)…...
洛谷P8814:解密 ← CSP-J 2022 复赛第2题
【题目来源】https://www.luogu.com.cn/problem/P8814https://www.acwing.com/problem/content/4732/【题目描述】 给定一个正整数 k,有 k 次询问,每次给定三个正整数 ni,ei,di,求两个正整数 pi,qi…...
Flutter实现CombineExecutor进行多个异步分组监听,监听第一个异步执行的开始和最后一个异步执行结束时机。
1.场景 我们在调用接口时,很多时候会同时调用多个接口,接口都是异步执行,我们很难知道调用的多个接口哪个会最后执行完成,我们有时候需要对最后一个接口执行完成的时机监听,所以基于该需求,设计了CombineE…...
2023 年最新Java 毕业设计选题题目参考,500道 Java 毕业设计题目,值得收藏
大家好,我是程序员徐师兄,最近有很多同学咨询,说毕业设计了,不知道选怎么题目好,有哪些是想需要注意的。 确实毕设选题实际上对很多同学来说一个大坑, 每年挖坑给自己跳的人太多太多,选题选得好…...
Mac电脑其他文件占用超过一大半的内存如何清理?
mac的存储空间时不时会提示内存已满,查看内存占用比例最大的居然是「其他文件」,「其他文件」是Mac无法识别的格式文件或应用插件扩展等等...如果你想要给Mac做一次彻底的磁盘空间清理,首当其冲可先对「其他文件」下手,那么我们该…...
geopandas 笔记: datasets 数据集
geopandas 自带的几个数据集 1 世界各个国家 import geopandas as gpd import pandas as pdpd.set_option(display.max_rows,None) gpd.read_file(gpd.datasets.get_path(naturalearth_lowres)) pop_est人口数量continent国家所在的大陆name国家的名称iso_a3国家的三个字母的…...
长胜证券:三大拐点共振 看好智能驾驶新一轮行情
摘要 【长胜证券:三大拐点共振 看好智能驾驭新一轮行情】长胜证券研报指出,全球共振,国内智驾商场正迎来三大拐点:1)技能上,“BEV Transformer数据闭环”新架构2023年开端上车,使得不依靠高精地…...
AIGC专栏5——EasyPhoto AI写真照片生成器 sd-webui插件介绍、安装与使用
AIGC专栏5——EasyPhoto AI写真照片生成器 插件安装与使用 学习前言源码下载地址技术原理储备(SD/Control/Lora)StableDiffusionControlNetLora EasyPhoto插件简介EasyPhoto插件安装安装方式一:Webui界面安装 (需要良好的网络&…...
【Python程序设计】 工厂模式【07/8】
一、说明 我们探索数据工程中使用的设计模式 - 软件设计中常见问题的可重用解决方案。 以下文章是有关 Python 数据工程系列文章的一部分,旨在帮助数据工程师、数据科学家、数据分析师、机器学习工程师或其他刚接触 Python 的人掌握基础知识。 迄今为止,…...
PHP8的多维数组-PHP8知识详解
今天分享的是php8的数组中的多维数组,主要内容有:多维数组的概念、创建和输出二维数组、创建和输出三维数组。 1、多维数组的概念 多维数组是包含一个或多个数组的数组。在多维数组中,主数组中的每一个元素也可以是一个数组,子数…...
【【STM32--28--IO引脚的复用功能】】
STM32–28–IO引脚的复用功能 STM32的IO复用功能 何为复用? 我们先了解一下何为通用 IO端口的输入或输出是由GPIO外设控制,我们称之为通用 复用: IO端口的输入或者是输出是由其他非GPIO外设控制就像经常说的USART 由 DR寄存器进行输出 STM32的IO复用功…...
CodeJock Active-X / COM v22.1.0 Crack
CodeJock Active-X / COM v22.1.0--这个支持 Unicode 啦, Unicode Unicode 创建专业应用程序,其中包含一整套高度可定制的用户界面组件,包括 Visual Studio 风格的对接窗格和 Office 风格的功能区、工具栏和菜单,为您的应用程序…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...
Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...
数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...
tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
