【go语言】select多路选择

select基础知识

select 是 Go 语言中用于处理通道操作的控制结构,它类似于 switch 语句,但专门用于通道的选择。select 语句使得一个 goroutine 可以等待多个通道操作,当其中任意一个通道操作可以进行时,就会执行相应的 case 分支。

select语句语法如下:

select {
case channel1 <- value1:// 如果 channel1 可以写入,执行这里
case value2 := <-channel2:// 如果 channel2 可以读取,执行这里
case value3, ok := <-channel3:// 如果 channel3 被关闭,并且有数据可读,执行这里
case <-time.After(time.Second):// 在超时时间内没有任何 case 可执行,执行这里
default:// 如果没有任何 case 可执行,执行这里
}

特性: 

  1. 如果多个 case 同时满足条件,Go 会随机选择一个执行。
  2. 如果没有 case 可以执行,且存在 default 分支,则执行 default
  3. 如果没有 default 分支,select 会阻塞,直到至少有一个 case 可执行。
  4. select 可以和 for 循环一起使用,用于不断地处理通道操作。

select 的主要用途是处理并发编程中的多个通道操作,例如处理超时、非阻塞通信等场景。

1. 超时控制

超时会比程序请求失败还可怕,为了避免主线程阻塞可以在select中设置超时中断。

示例代码如下:通过多路选择等待任务完成,如果超时就直接执行其他的处理程序

package mainimport ("fmt""time"
)// 超时控制
func main() {select {case re := <-AsynService():fmt.Print("任务完成", re)case <-time.After(time.Millisecond * 3000):fmt.Print("超时啦")//default://	fmt.Print("不能阻塞")}}// 服务
func service() string {time.Sleep(time.Millisecond * 3000)return "finish"
}// 异步启动服务
func AsynService() chan string {rechan := make(chan string, 1)go func() {res := service()time.Sleep(time.Millisecond * 1000)rechan <- res}()return rechan
}

2. 任务取消

(1)获取取消通知

// 3.select判断任务是否取消
func isCanceled(cn chan struct{}) bool {select {case <-cn:fmt.Println("任务取消")return truedefault:fmt.Println("任务不取消,继续执行")return false}
}

(2)发送取消消息

// 1.普通向cancel通道发送取消通知,这种做法需要事先知道有多少个正在执行的任务
func cancel1(cn chan struct{}) {cn <- struct{}{}
}// 2.向采取close方法关闭所有任务
func cancel2(cn chan struct{}) {close(cn)
}

(3)测试

// 测试任务取消
func TestCancel(t *testing.T) {cn := make(chan struct{})for i := 1; i < 6; i++ {go func(cn chan struct{}) {for {if isCanceled(cn) {break} else {time.Sleep(time.Millisecond * 1000)}}fmt.Println("任务取消")}(cn)}cancel2(cn)}

六个go程进行监听任务是否取消,普通发送取消通知只会取消一个go程,关闭通道可以取消所有在监听的go程。

3. Context任务取消

(1)Context介绍

在 Go 语言中,context.Context 是一个标准库中非常常用的接口,它提供了在多个 goroutine 之间传递请求范围的截止日期、取消信号、存储值等信息的途径。context.Context 主要用于在函数之间传递请求的截止日期、取消信号、跟踪信息以及其他请求范围的值。

type Context interface {Deadline() (deadline time.Time, ok bool)Done() <-chan struct{}Err() errorValue(key interface{}) interface{}
}
  • Deadline():返回 Context 的截止日期(即取消的时间点)和一个布尔值,表示是否设置了截止日期。
  • Done():返回一个 <-chan struct{} 类型的通道,该通道关闭时表示 Context 被取消或者达到了截止日期。
  • Err():返回一个错误,表示 Context 被取消的原因。
  • Value(key interface{}):根据给定的键返回相关联的值,通常用于传递请求范围的值。

context 包还提供了一些函数用于创建和操作 Context

  • context.Background():返回一个空的 Context,常用于表示整个请求生命周期。
  • context.TODO()TODO 表示 "to do",返回一个空的、不可取消的 Context
  • context.WithCancel(parent Context) (ctx Context, cancel CancelFunc):返回一个可取消的 Context 和一个对应的 CancelFunc,可以用来取消该 Context
  • context.WithDeadline(parent Context, d time.Time) (Context, CancelFunc):返回一个带有截止日期的 Context
  • context.WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc):返回一个带有超时时间的 Context
  • context.WithValue(parent Context, key, val interface{}) Context:返回一个包含指定键值对的 Context

(2)任务取消

发送取消消息:

func isCanceled2(ctx context.Context) bool {select {case <-ctx.Done():return truedefault:return false}
}

我们可以看一下ctx.Done()的源码:

Done()方法返回一个channel,直接读取这个channel将会被阻塞,让我们看一下cancelCtx源码:

由上面的结构体可以知道这里c.done是一个原子操作的值,采用懒加载方法,被第一次调用的cancel方法关闭。
调用Done函数时已经存在一个取消通道时就直接返回,当是第一个调用的就创建channel并返回,都是并发安全的。

测试:

func TestContextCancel(t *testing.T) {ctx, cancel := context.WithCancel(context.Background())for i := 1; i < 6; i++ {go func(i int, ctx context.Context) {for {if isCanceled2(ctx) {break} else {time.Sleep(time.Millisecond * 100)}}fmt.Println(i, "Cancelled")}(i, ctx)}cancel()time.Sleep(time.Second * 1)
}

这里通过context.Background()函数获得顶级context,通过WithCancel函数获取一个子上下文和一个取消函数,通过取消顶级context可以取消所有子上下文达到任务取消目的,或者是子上下文其自身取消。

 让我们看一下cancel方法:cancel方法关闭c.done也就是关闭了这个chan通道通知任务取消,同时也递归取消所有的子上下文,如果removeFromParent参数为true将会从父context移除掉当前子context。

// cancel closes c.done, cancels each of c's children, and, if
// removeFromParent is true, removes c from its parent's children.
// cancel sets c.cause to cause if this is the first time c is canceled.
func (c *cancelCtx) cancel(removeFromParent bool, err, cause error) {if err == nil {panic("context: internal error: missing cancel error")}if cause == nil {cause = err}c.mu.Lock()if c.err != nil {c.mu.Unlock()return // already canceled}c.err = errc.cause = caused, _ := c.done.Load().(chan struct{})if d == nil {c.done.Store(closedchan)} else {close(d)}for child := range c.children {// NOTE: acquiring the child's lock while holding parent's lock.child.cancel(false, err, cause)}c.children = nilc.mu.Unlock()if removeFromParent {removeChild(c.Context, c)}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/600106.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Reids原理及简单命令

目录 1.关系数据库与非关系型数据库 关系型数据库 非关系型数据库 关系型数据库和非关系型数据库区别 数据存储方式不同 扩展方式不同 对事务性的支持不同 总结&#xff1a; 2. Redis简介 什么是reids reids优点 reids使用场景&#xff1a; reids快的原因 Redis数…

功能强大且直观的日程和任务管理工具—Things 3 for Mac

在现代生活中&#xff0c;我们面对着繁忙的日程安排和众多的任务&#xff0c;我们需要一款高效的工具来帮助我们管理和组织这些事务。而事务管理的首选工具&#xff0c;非 Things 3 for Mac 莫属。 Things 3 for Mac 是一款功能强大且直观的日程和任务管理工具。它的设计简洁&…

Vue3——element-plus表格组件怎样得到当前行的id

实现方法&#xff1a; <el-table-column property"address" label"操作" show-overflow-tooltip header-align"center" v-slot"scope"><el-button type"success" click"editBtn(scope.row.id)">编辑…

01-线程池项目背景:C++的数据库操作

从0开始学习C与数据库的联动 1.原始方式-使用MySQL Connector/C 提供的API查询 1.1 数据库预操作 我的本地电脑上有mysql数据库&#xff0c;里面预先创建了一个database名叫chat&#xff0c;用户名root&#xff0c;密码password。 1.2 Visual Studio预操作 在Windows上使用…

【unity】Obi插件架构组成(参数详细解释)——解算器四面板设置、三种更新器、参与者介绍

文章目录 一、架构&#xff08;Architecture&#xff09;1.1 Obi解算器&#xff08;ObiSolver&#xff09;1.2 ObiUpdater1.3 ObiActorBlueprint1.4 Obi参与者&#xff08;ObiActor&#xff0c;如ObiRope等&#xff09; 二、Obi解算器&#xff08;ObiSolver&#xff09;2.1 解算…

win11家庭版开启远程桌面功能

win11家庭版不支持远程桌面 下载补丁 https://download.csdn.net/download/yonggeit/88706714 用谷歌浏览器会提示危险文件&#xff0c;选择“保留危险文件”即可&#xff0c;如果大家不放心&#xff0c;可用杀软进行查杀。 解压后 选择“install.bat”右键选择“以管理员身份…

【C语言刷题每日一题#牛客网BC107】矩阵转置

目录 问题描述 思路逐步分析 完整代码实现 结果测试 问题描述 思路逐步分析 首先&#xff0c;根据输入的描述&#xff0c;第一行输入的是两个整数n和m&#xff0c;分别表示一个矩阵&#xff08;二维数组&#xff09;的行和列&#xff0c;并且行和列不超过10 根据要求&…

鸡目标检测数据集VOC格式500张

鸡&#xff0c;一种家禽&#xff0c;是人类的重要食物来源之一&#xff0c;也是农业生产中的重要组成部分。 鸡的外观相对较为简单&#xff0c;身体呈圆锥形&#xff0c;羽毛密集&#xff0c;双翅短小&#xff0c;无法飞行。鸡的头部较小&#xff0c;嘴巴尖锐&#xff0c;方便…

电商要怎么学?企业如何进行数字化转型打破市场僵局?

电商要怎么学&#xff1f;企业如何进行数字化转型打破市场僵局&#xff1f; 电商的学习需要从多个方面入手&#xff0c;首先需要了解电商的基本概念和原理&#xff0c;包括电商平台的运营模式、商品推广、客户服务等。此外&#xff0c;还需要掌握电商平台的操作技能&#xff0c…

Pygame中监控键盘按键的方法

1 事件与队列 在Pygame中&#xff0c;将用户对游戏的操作叫做“事件”。键盘按键是一种事件&#xff0c;鼠标点击和游戏手柄的输入也是一种事件。在Pygame的子模块locals中&#xff0c;对这些事件进行了定义。当用户通过键盘、鼠标或者游戏手柄对游戏进行操作后&#xff0c;产…

SpringBoot项目部署(Docker)——通过Dockerfile将打包好的jar包创建成镜像 在IDEA中配置docker,一键启动容器 用swagger进行测试

目录 引出SpringBoot项目部署&#xff08;jar包&#xff09;Dockefile初识idea配置docker在Linux中配置docker remote api配置idea docker插件 部署项目Springboot整合Dockerfile准备项目创建Dockerfile文件进行测试 总结 引出 1.Dockerfile命令初识&#xff0c;CMD…; 2.idea配…

Fiddler抓取HTTPS最全(强)攻略

对于想抓取HTTPS的测试初学者来说&#xff0c;常用的工具就是fiddler。可是在初学时&#xff0c;大家对于fiddler如何抓取HTTPS真是伤了脑筋&#xff0c;可能你一步步按着网上的帖子成功了&#xff0c;那当然是极好的。 有可能没有成功&#xff0c;这时候你就很抓狂了&#xff…

Unity3D Shader 之透视效果XRay

1、 Shader "Unlit/XRay" {Properties{_MainTex("Texture", 2D) "white" {}// 漫反射_Diffuse("Diffuse", COLOR) (1,1,1,1)// XRay 效果_XRayColor("XRay Color", COLOR) (0,1,1,1)_XRayPower("XRay Power",…

Mysql 将表里的两列值数据互换

示例&#xff1a; 需要将表中的 两个订单号互换 方案&#xff1a; 将同一张表数据做 临时数据 和主表 做数据交互 。 update 表 as main, 表 as temp set main.bill_no temp.track_bill_no, main.track_bill_no temp.bill_no where main.id temp.id…

新手小白如何搭建自己的服务器

由于近期六年前的域名到期了&#xff0c;阿里云的客服电话&#xff0c;正好提醒了我需要管理下这方面的东西&#xff0c; 正好看到阿里云的服务器99/年&#xff0c;而且可以原价续费两年&#xff0c;截止日期为2026年3月&#xff0c;所以我还是剁手了。 借着这次机会写一部分建…

分布式(7)

目录 31.基于Zookeeper如何实现分布式锁&#xff1f; 32.什么是ACID&#xff1f; 33.什么是分布式的XA协议&#xff1f; 34.什么是2PC&#xff1f; 35.什么是3PC&#xff1f; 31.基于Zookeeper如何实现分布式锁&#xff1f; 顺序节点 创建一个用于发号的节点“/test/lock…

应用在游戏机触摸屏中的触摸感应芯片

触屏游戏机的屏幕是由液晶屏和触控层组成的。触控层分为电容式触屏和电阻式触屏两种。电容式触屏是将悬空电极和屏幕玻璃上的电极组成静电场,当人体接近屏幕时,就会改变静电场分布,从而实现触摸的位置探测。而电阻式触屏则是利用玻璃上的两层电极之间通电形成一个电阻值,当手指…

【python入门】day19:学生管理系统需求分析、系统设计、主函数设计

需求分析 应具备功能—— 添加学生及成绩信息&#xff1b; 将学生信息保存到文件中&#xff1b; 修改和删除学生信息&#xff1b; 查询学生信息&#xff1b; 根据学生成绩进行排序&#xff1b; 统计学生的总分 系统设计 1.录入学生信息模块 2.查找 3.删除 4.修改 5.成绩排名…

数据分析求职-简历准备

简历在整个求职过程中的重要性不言而喻&#xff0c;今天咱们来聊求职过程中简历准备的那些事儿~ 1. 简历究竟有啥用 求职的流程简单说就是&#xff1a;网申->笔试->面试->offer 其中网申环节&#xff0c;简历100%决定了你的通过与否&#xff0c;这个点大家都知道。…

计算机Java项目|Springboot+vue 学生心理咨询评估系统

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容&#xff1a;Java项目、Python项目、前端项目、人工智能与大数据、简…