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

Go并发可视化解释 - Select语句

昨天,我发布了一篇文章,用可视化的方式解释了Golang中通道(Channel)的工作原理。如果你对通道的理解仍然存在困难,最好呢请在阅读本文之前先查看那篇文章。作为一个快速的复习:Partier、Candier 和 Stringer 经营着一家咖啡店。Partier 协助从顾客接收订单,然后将这些订单传递给厨房,Candier 和 Stringer 制作咖啡。

49892cf1f41bacfb46d4aadadf9b88b0.png
1*SuZghSKVBqKMuv7E25hWPw.png

Gophers 咖啡馆

在本文中,我将以视觉方式解释 select 语句,这是另一个在Go应用程序中处理并发的强大工具。Gophers 和他们的想象中的咖啡馆仍然会是我的伙伴,但这次,让我们聚焦在 Partier 和订单部分。

场景

Gophers 咖啡馆意识到越来越多的顾客想通过食品外卖应用订购咖啡。因此,除了现场点餐外,他们还选择了一款食品外卖应用。Partier 同时监听来自这两个通道的订单,并将这些订单通过另一个通道 queue 转发给 Candier 和 Stringer。

select {
case order := <-appOrders:queue <- order
case order := <-inShopOrders:queue <- order
}

当任何一个通道接收到订单时,Partier 会将其转发到 queue 通道。

a30643d7faa8caec4ff3c0f2a954ba0e.png
bb2c1d6a145925553262093510ac42d5.png

如果两个通道都有订单,其中之一将被选择。在真实的咖啡馆中,来自 inShopOrders 的订单可能会被优先处理。然而,在Go应用程序中,我们不能保证会选择哪个订单。还请注意,select 语句的每次执行只会选取一个订单,Partier 不会先选择一个订单,然后再选择另一个订单。尽管如此,在许多应用程序中,select 语句通常在 for 循环内部,使得前一次迭代中留下的订单在下一次迭代中有机会被选取。

for {select {case order := <-appOrders:queue <- ordercase order := <-inShopOrders:queue <- order}
}

但是,如果两个通道都有订单,它们将再次进行公平竞争。

04875e5751783e5afef1dfaec1df8735.png

默认分支

在非高峰时段,订单不多,Partier 在等待上花费了大量时间。他认为,通过做其他事情,例如清洁桌子,他可以更有成效地利用时间。这可以通过 default 实现。

for {select {case order := <-appOrders:log.Println("There is an order coming from appOrders channel")queue <- ordercase order := <-inShopOrders:log.Println("There is an order coming from inShopOrders channel")queue <- orderdefault:log.Println("There is no order on both channels, I will do cleaning instead")doCleaning()}
}

time.After()

通常,time.After(duration) 与 select 一起使用,以防止永远等待。与 default 立即在没有可用通道时执行不同,time.After(duration) 创建一个普通的 <-chan Time,等待 duration 过去,然后在返回的通道上发送当前时间。这个通道在 select 语句中与其他通道一样被处理。正如你所看到的,select 语句中的通道可以是不同类型的。

shouldClose := false
closeHourCh := time.After(8 * time.Hour)for !shouldClose {select {case order := <-appOrders:log.Println("There is an order coming from appOrders channel")queue <- ordercase order := <-inShopOrders:log.Println("There is an order coming from inShopOrders channel")queue <- ordercase now := <-closeHourCh:log.Printf("It is %v now, the shop is closing\n", now)shouldClose = truedefault:log.Println("There is no order on both channels, I will go cleaning instead")doCleaning()}
}log.Println("Shop is closed, I'm going home now. Bye!")

在处理远程API调用时,这种技术非常常见,因为我们不能保证远程服务器何时返回或是否返回。有了 context,我们通常不需要这样做。

responseChannel := make(chan interface{})
timer := time.NewTimer(timeout)select {
case resp := <-responseChannel:log.Println("Processing response")processResponse(resp)timer.Stop()
case <-timer.C:log.Println("Time out, giving up")
}

示例代码

让我们以一个完整的虚构咖啡馆代码结束本文。这里还有一件需要注意的事情,从关闭的通道中选择将总是立即返回。因此,如果您认为有必要,使用“comma ok”习惯用法。亲自动手编码是学习编程的最佳方式。因此,如果您对 select 不太熟悉,我建议您在IDE上复制并尝试修改此代码。

祝您编码愉快!

package mainimport ("fmt""log""time"
)func main() {appOrders := make(chan order, 3)inShopOrders := make(chan order, 3)queue := make(chan order, 3)go func() {for i := 0; i < 6; i++ {appOrders <- order(100 + i)time.Sleep(10 * time.Second)}close(appOrders)}()go func() {for i := 0; i < 4; i++ {inShopOrders <- order(200 + i)time.Sleep(15 * time.Second)}close(inShopOrders)}()go partier(appOrders, inShopOrders, queue)for o := range queue {log.Printf("Served %s\n", o)}log.Println("Done!")
}func partier(appOrders <-chan order, inShopOrders <-chan order, queue chan<- order) {shouldClose := falsecloseTimeCh := time.After(1 * time.Minute)for !shouldClose {select {case ord, ok := <-appOrders:if ok {log.Printf("There is %s coming from appOrders channel\n", ord)queue <- ord}case ord, ok := <-inShopOrders:if ok {log.Printf("There is %s coming from inShopOrders channel\n", ord)queue <- ord}case now := <-closeTimeCh:log.Printf("It is %v now, the shop is closing\n", now)shouldClose = truedefault:log.Println("There is no order on both channels, I will go cleaning instead")doCleaning()}}close(queue)log.Println("Shop is closed, I'm going home now. Bye!")
}func doCleaning() {time.Sleep(5 * time.Second)log.Println("Partier: Cleaning done")
}type order intfunc (o order) String() string {return fmt.Sprintf("order-%02d", o)
}

感谢您一直阅读到文章末尾。请考虑关注下作者啦~

相关文章:

Go并发可视化解释 - Select语句

昨天&#xff0c;我发布了一篇文章&#xff0c;用可视化的方式解释了Golang中通道&#xff08;Channel&#xff09;的工作原理。如果你对通道的理解仍然存在困难&#xff0c;最好呢请在阅读本文之前先查看那篇文章。作为一个快速的复习&#xff1a;Partier、Candier 和 Stringe…...

在线SM4(国密)加密解密工具

在线SM4(国密)加密解密工具...

golang的类型断言语法

例子1 在 Go 中&#xff0c;err.(interface{ Timeout() bool }) 是一个类型断言语法。它用于检查一个接口类型的变量 err 是否实现了一个带有 Timeout() bool 方法的接口。 具体而言&#xff0c;该类型断言的语法如下&#xff1a; if v, ok : err.(interface{ Timeout() boo…...

提速换挡 | 至真科技用技术打破业务壁垒,助力出海破局增长

各个行业都在谈出海&#xff0c;但真正成功的又有多少&#xff1f; 李宁出海十年海外业务收入占比仅有1.3%&#xff0c;走出去战略基本失败。 京东出海业务磕磕绊绊&#xff0c;九年过去国际化业务至今在财报上都不配拥有姓名。 几百万砸出去买量&#xff0c;一点水花都没有…...

第3篇:vscode搭建esp32 arduino开发环境

第1篇:Arduino与ESP32开发板的安装方法 第2篇:ESP32 helloword第一个程序示范点亮板载LED 1.下载vscode并安装 https://code.visualstudio.com/ 运行VSCodeUserSetup-x64-1.80.1.exe 2.点击扩展&#xff0c;搜索arduino,并点击安装 3.点击扩展设置&#xff0c;配置arduino…...

Apache Shiro是什么

特点 Apache Shiro是一个强大且易用的Java安全框架,用于身份验证、授权、会话管理和加密。它的设计目标是简化应用程序的安全性实现,使开发人员能够更轻松地处理各种安全性问题,从而提高应用程序的安全性和可维护性。下面是一些Apache Shiro的关键特点和概念: 特点和概念…...

Socket基本原理

一、简单介绍 Socket&#xff0c;又称套接字&#xff0c;是Linux跨进程通信&#xff08;IPC&#xff0c;Inter Process Communication&#xff09;方式的一种。相比于其他IPC方式&#xff0c;Socket牛逼在于可做到同一台主机内跨进程通信&#xff0c;不同主机间的跨进程通信。…...

Docker容器:本地私有仓库、harbor私有仓库部署与管理

文章目录 Docker容器&#xff1a;本地私有仓库、harbor私有仓库部署与管理一.本地私有仓库1.本地私有仓库概述2.搭建本地私有仓库3.容器重启策略简介 二.harbor私有仓库部署与管理1.什么是harbor2.Harbor的特性3、Harbor的构成4.Harbor私有仓库架构及数据流向5.harbor部署及配置…...

Mobx在非react组件中修改数据,在ts/js中修改数据实现响应式更新

我们都之前在封装mobx作为数据存储的时候&#xff0c;使用到了useContext作为包裹&#xff0c;将store变成了一个hooks使用&#xff0c;封装代码: import React from react import UserInfo from ./user import Setting from ./seting import NoteStore from ./noteclass Stor…...

什么是异步编程?什么是回调地狱(callback hell)以及如何避免它?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 异步编程⭐ 回调地狱&#xff08;Callback Hell&#xff09;⭐ 如何避免回调地狱1. 使用Promise2. 使用async/await3. 模块化和分离 ⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订…...

Java8 Stream流常见操作--持续更新中

创建新数组 List<Fruit> newList fruits.stream().map(f -> new Fruit(f.getId(), f.getName() "s", f.getCountry())).collect(Collectors.toList())筛选数组 Map<Boolean, List<TransferData>> preAvg list.stream().collect(Collectors…...

【Linux】多线程概念线程控制

文章目录 多线程概念Linux下进程和线程的关系pid本质上是轻量级进程id&#xff0c;换句话说&#xff0c;就是线程IDLinux内核是如何创建一个线程的线程的共享和独有线程的优缺点 线程控制POSIX线程库线程创建线程终止线程等待线程分离 多线程概念 Linux下进程和线程的关系 在…...

Qt --- 自定义提示框 类似QMessagebox

QMessageBox::information(NULL, QString("title"), QString("I am information")); 以下是自定义提示框的代码&#xff0c;有图有真相&#xff01;提示框大部分都采用模态的形式&#xff0c;关于模态也不再多提&#xff01;所以父类为QDialog&#xff0c;…...

Redis 分布式锁与 Redlock 算法实现

Redis 分布式锁与 Redlock 算法实现 一、简介1. Redis的分布式锁2. 分布式锁的实现原理 二、Redis 分布式锁使用场景1. 分布式系统中数据资源的互斥访问2. 分布式环境中多个节点之间的协作3. 常见场景及应用 三、Redlock算法的原理与实现1. Redlock算法的背景2. Redlock算法的原…...

【附安装包】Inventor2024安装教程 机械制图|三维制图

软件下载 软件&#xff1a;Inventor版本&#xff1a;2024语言&#xff1a;简体中文大小&#xff1a;5.61G安装环境&#xff1a;Win11/Win10/Win8/Win7硬件要求&#xff1a;CPU2.5GHz 内存8G(或更高&#xff09;下载通道①百度网盘丨64位下载链接&#xff1a;https://pan.baidu…...

c++ 判断基类指针指向的真实对象类型

在 c 面向对象使用中&#xff0c;我们常常会定义一个基类类型的指针&#xff0c;在运行过程中&#xff0c;这个指针可能指向一个基类类型的对象&#xff0c;也可能指向的是其子类类型的对象&#xff0c;那现在问题来了&#xff0c;我们如何去判断这个指针到底执行了一个什么类型…...

退出屏保前玩一把游戏吧!webBrowser中网页如何调用.NET方法

本文主要以 HackerScreenSaver 新功能的开发经历介绍 webBrowser中网页如何调用.NET方法的过程。 1. 背景 之前开源了一款名为 HackerScreenSaver 的 Windows 屏保程序。该程序具有模拟黑客炫酷界面的特点&#xff0c;用户可以将自定义的网页作为锁屏界面。不久前&#xff0c;…...

hive-列转行

转成 select customer_code,product_type from temp.temp_xx LATERAL VIEW explode(SPLIT(product_types,,)) table_tmp AS product_type where customer_code K100515182...

【网络】IP网络层和数据链路层

IP协议详解 1.概念 1.1 四层模型 应用层&#xff1a;解决如何传输数据&#xff08;依照什么格式/协议处理数据&#xff09;的问题传输层&#xff1a;解决可靠性问题网络层&#xff1a;数据往哪里传&#xff0c;怎么找到目标主机数据链路层&#xff08;物理层&#xff09;&…...

基于Spring Gateway路由判断器实现各种灰度发布场景

文章目录 1、灰度发布实现1.1 按随机用户的流量百分比实现灰度1.2 按人群划分实现的灰度1.2.1 通过Header信息实现灰度1.2.2 通过Query信息实现灰度1.2.3 通过RemoteAdd判断来源IP实现灰度 2、路由判断器2.1. After2.2. Before2.3. Between2.4. Cookie2.5. Header2.6. Host2.7.…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

【力扣数据库知识手册笔记】索引

索引 索引的优缺点 优点1. 通过创建唯一性索引&#xff0c;可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度&#xff08;创建索引的主要原因&#xff09;。3. 可以加速表和表之间的连接&#xff0c;实现数据的参考完整性。4. 可以在查询过程中&#xff0c;…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词

Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵&#xff0c;其中每行&#xff0c;每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid&#xff0c;其中有多少个 3 3 的 “幻方” 子矩阵&am…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...