Golang 里的 context
context 的作用
go 的编程中,常常会在一个 goroutine 中启动多个 goroutine,然后有可能在这些 goroutine 中又启动多个 goroutine。

如上图,在 main 函数中,启动了一个 goroutine A 和 goroutine B,然后 goroutine A 中又启动了 goroutine A1 和 goroutine A2,goroutine B 中也是。
有时候,我们可能想要取消当前的处理,这个时候自然而然的也要取消子协程的执行进程。这个时候就需要一种机制来做这件事。context 就是设计来做这件事的。
比如在 web 应用中,当子协程的某些处理时间过长的时候,我们可能想要终止下游的处理,防止协程长期占用资源。保证其他客户端的请求正常处理。
context 的不同类型
context.Background
往往用做父 context,比如在 main 中定义的 context,然后在 main 中将这个 context 传递给子协程。
context.TODO
不需要使用什么类型的 context 的时候,使用这个 context.TODO
context.WithTimeout
我们需要对子 goroutine 做一些超时控制的时候,使用这个 context,比如超过多少秒就不再做处理。
context.WithDeadline
和 context.WithTimeout 类似,只不过参数是一个 time.Time,而不是 time.Duration
context.WithCancel
如果在父 goroutine 里面需要在某些情况下取消执行的时候,可以使用这种 context。
实例
context.Background
package mainimport ("context""fmt""time"
)func main() {ctx := context.Background()go func(ctx2 context.Context) {fmt.Println("ctx2")ctx3, cancel := context.WithCancel(ctx2)go func(ctx4 context.Context) {fmt.Println("ctx4")}(ctx3)cancel()}(ctx)time.Sleep(time.Millisecond * 5)
}
在 main 入口里顶层的 context 使用 context.Background,子 goroutine 里面可以针对实际情况基于父 context 派生新的 context,比如,加入如果需要对子 goroutine 做一些条件性的取消操作,就可以像上面那样使用 ctx3, cancel := context.WithCancel(ctx2) 来基于父 context 创建一个新的 context,然后我们可以通过 cancel 来给子 goroutine 发送取消信号。
注意这里的用语,这里说发送取消信号,因为事实上是否取消后续操作的控制权还是在子 goroutine 里面。但是子 goroutine 有义务停止当前 goroutine 的操作。
个人觉得一个原因是,可能子 goroutine 里面有一些清理操作需要进行,比如写个 Log 说当前操作被取消了,这种情况下直接强行取消并不是很好的选择,所以把控制权交给子 goroutine。
这一点可能在大多数文章里面可能没有提到,但是笔者觉得如果明白了这一点的话,对于理解 context 的工作机制很有帮助。
这种机制的感觉有点像是,虽然你有权力不停止当前操作,但是你有义务去停止当前的处理,给你这种权力只是为了让你有点反应时间。
context.TODO
这个就跳过吧,好像没什么好说的
context.WithTimeout
func ExampleContextWithTimeout() {// 10 毫秒超时时间// context.WithTimeout 也返回了一个 cancel 函数,但是我们这里不需要,所以忽略了。ctx, _ := context.WithTimeout(context.Background(), time.Millisecond * 10)var wg sync.WaitGroupwg.Add(1)go func(ctx context.Context) {defer wg.Done()// sleep 20 毫秒模拟耗时任务time.Sleep(time.Millisecond * 20)select {case <-ctx.Done():// 因为已经超时了,所以 ctx.Done() 返回的 channel 直接返回了,因为已经关闭了// 我们可以使用 ctx.Err() 来查看具体的原因,这里是 "context deadline exceeded"fmt.Println(ctx.Err())returndefault:fmt.Println("in goroutine")}}(ctx)wg.Wait()// Output:// context deadline exceeded
}
context.WithDeadline
func ExampleContextWithDeadline() {// 10 毫秒超时时间// context.WithDeadline 也返回了一个 cancel 函数,但是我们这里不需要,所以忽略了。ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(time.Millisecond * 10))var wg sync.WaitGroupwg.Add(1)go func(ctx context.Context) {defer wg.Done()// sleep 20 毫秒模拟耗时任务time.Sleep(time.Millisecond * 20)select {case <-ctx.Done():// 因为已经到达了 deadline,所以 ctx.Done() 返回的 channel 直接返回了,因为这个 channel 已经关闭了// ctx.Err() 同 context.WithTimeout,也是 "context deadline exceeded"fmt.Println(ctx.Err())returndefault:fmt.Println("in goroutine")}}(ctx)wg.Wait()// Output:// context deadline exceeded
}
context.WithCancel
func ExampleContextWithCancel() {// context.WithCancel 返回的第二个值是一个可以调用的函数,调用的时候子协程里面的 context 可以通过 ctx.Done() 获取到取消的信号ctx, cancel := context.WithCancel(context.Background())var wg sync.WaitGroupwg.Add(1)go func(ctx context.Context) {defer wg.Done()for {select {case <-ctx.Done():fmt.Println(ctx.Err())returndefault:fmt.Println("ExampleContextWithCancel default")}}}(ctx)cancel()wg.Wait()// Output:// context canceled
}
其实我们可以发现,context.WithTimeout 和 context.WithDeadline 也返回了一个 cancelFunc,context.WithCancel 返回的 cancelFunc 和这个的效果一样。
只不过 context.WithTimeout 和 context.WithDeadline 多提供了一个时间上的控制。
总结
-
golang 中的 context 提供了一种父子 goroutine 之间沟通的机制
-
context.WithTimeout、context.WithDeadline、context.WithCancel 都返回一个新的 context 和一个 cancelFunc,cancelFunc 可以用来取消子 goroutine
-
goroutine 最终是否停止取决于子 goroutine 本身,但是我们有必要去监听 ctx.Done() 来根据父 goroutine 传递的信号来决定是否继续执行还是直接返回。
相关文章:
Golang 里的 context
context 的作用 go 的编程中,常常会在一个 goroutine 中启动多个 goroutine,然后有可能在这些 goroutine 中又启动多个 goroutine。 如上图,在 main 函数中,启动了一个 goroutine A 和 goroutine B,然后 goroutine A …...
PHP短链接url还原成长链接
在开发过程中,碰到了需要校验用户回填的短链接是不是系统所需要的,于是就需要还原找出短链接所对应的长链接。 长链接转短链接 在百度上搜索程序员,跳转页面后的url就是一个长链接。当然你可以从任何地方复制一个长链接过来。 长链接 http…...
redis原理(三)redis命令
一、字符串命令: 1、字符串基本操作: 2、自增自减 :如果一个值可以被解释为十进制整数或者浮点数,redis允许用户对这个字符串进行INCR*、DECR*操作。 (1)INCR key:将键存储的值的值加1。 &a…...
教程:在Django中实现微信授权登录
教程:在Django中实现微信授权登录 本教程将引导您如何在Django项目中实现微信授权登录。在本教程中,我们将使用自定义的用户模型User,并通过微信提供的API来进行用户认证。 在进行以下教程之前,请确保你已经在微信开放平台添加了…...
YOLOv5改进 | 主干篇 | 12月份最新成果TransNeXt特征提取网络(全网首发)
一、本文介绍 本文给大家带来的改进机制是TransNeXt特征提取网络,其发表于2023年的12月份是一个最新最前沿的网络模型,将其应用在我们的特征提取网络来提取特征,同时本文给大家解决其自带的一个报错,通过结合聚合的像素聚焦注意力和卷积GLU&…...
【java八股文】之计算机网络系列篇
1、TCP/IP和UDP模型 TCP/IP分层(4层):应用层,传输层,网络层,数据链路层 网络的七层架构 (7层):应用层,表示层,会话层,传输层ÿ…...
SpringAMQP的使用
1. 简介: SpringAMQP是基于RabbitMQ封装的一套模板,并且还利用SpringBoot对其实现了自动装配,使用起来非常方便。 SpringAmqp的官方地址:https://spring.io/projects/spring-amqp SpringAMQP提供了三个功能: 自动声…...
MATLAB - 使用运动学 DH 参数构建机械臂
系列文章目录 前言 一、 使用 Puma560 机械手机器人的 Denavit-Hartenberg (DH) 参数,逐步建立刚体树形机器人模型。在连接每个关节时,指定其相对 DH 参数。可视化机器人坐标系,并与最终模型进行交互。 DH 参数定义了每个刚体通过关节与其父…...
2024年腾讯云新用户优惠云服务器价格多少?
腾讯云服务器租用价格表:轻量应用服务器2核2G3M价格62元一年、2核2G4M价格118元一年,540元三年、2核4G5M带宽218元一年,2核4G5M带宽756元三年、轻量4核8G12M服务器446元一年、646元15个月,云服务器CVM S5实例2核2G配置280.8元一年…...
如何在原型中实现继承和多态
在JavaScript中,我们可以通过原型链来实现继承。以下是如何在原型中实现继承的例子: // 定义一个动物原型 var Animal function() {}; Animal.prototype.move function() { console.log(‘This animal can move.’); }; // 定义一个狗的原型…...
MySQL/Oracle 的 字符串拼接
目录 MySQL、Oracle 的 字符串拼接1、MySQL 的字符串拼接1.1 CONCAT(str1,str2,...) : 可以拼接多个字符串1.2 CONCAT_WS(separator,str1,str2,...) : 指定分隔符拼接多个字符串1.3 GROUP_CONCAT(expr) : 聚合函数,用于将多行的值连接成一个字符串。 2、Oracle 的字…...
【Java SE语法篇】10.String类
📚博客主页:爱敲代码的小杨. ✨专栏:《Java SE语法》 ❤️感谢大家点赞👍🏻收藏⭐评论✍🏻,您的三连就是我持续更新的动力❤️ 文章目录 前言1. String类1.1 字符串的构造1.2 String对象的比…...
【Python】数据可视化--基于TMDB_5000_Movie数据集
一、数据准备 tmdb_5000_movie数据集下载 二、数据预处理 观察数据集合情况 import pandas as pd import ast import warnings warnings.filterwarnings(ignore) # 加载数据集 df pd.read_csv(tmdb_5000_movies.csv) # 查看数据集信息 print(df.info()) 由于原数据集包含的…...
学习Vue的插槽总结
今天学习了Vue的插槽,在这之前学习使用组件的使用还没有试过在父组件中给子组件插入html结构,今天学习的插槽正是拿来实现这一功能的,这也是一种组件中通信的方式,首先插槽分为三类:默认插槽、具名插槽、作用域插槽。接…...
第九篇 API设计原则与最佳实践
深入浅出HTTP请求前后端交互系列专题 第一章 引言-HTTP协议基础概念和前后端分离架构请求交互概述 第二章 HTTP请求方法、状态码详解与缓存机制解析 第三章 前端发起HTTP请求 第四章 前后端数据交换格式详解 第五章 跨域资源共享(CORS):现代W…...
新版AndroidStudio配置maven阿里云镜像
project下的build.gradle: // Top-level build file where you can add configuration options common to all sub-projects/modules. // 注意jdk版本需要17以上,因为8.1.3的gradle需要jdk17以上 //plugins { // id com.android.application version…...
【OSG案例详细分析与讲解】之十一:【多效果的3D动画】
目录 一、【多效果的3D动画】前言 二、【多效果的3D动画】实现效果...
一道使用LinkedList和Stack解决的算法题
一、无法吃午餐的学生数量 学校的自助午餐提供圆形和方形的三明治,分别用数字 0 和 1 表示。所有学生站在一个队列里,每个学生要么喜欢圆形的要么喜欢方形的。 餐厅里三明治的数量与学生的数量相同。所有三明治都放在一个 栈 里,每一轮&#…...
通用外设-W25Q64
前言 一、SPI通信 二、W25Q64基初时序 1.各种命令代码 2.代码 1.写使能指令 2.读取芯片是否忙碌状态并等待 3.写入数据 4.擦除函数操作 5.读取代码 三.验证 四.擦除说明 总结 前言 在单片机中一般32K FLASH就够用了,但是当我们使用图片或其他大量数据时…...
Spring MVC MVC介绍和入门案例
1.SpringMVC概述 1.1.MVC介绍 MVC是一种设计模式,将软件按照模型、视图、控制器来划分: M:Model,模型层,指工程中的JavaBean,作用是处理数据 JavaBean分为两类: 一类称为数据承载Bean…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
C语言中提供的第三方库之哈希表实现
一. 简介 前面一篇文章简单学习了C语言中第三方库(uthash库)提供对哈希表的操作,文章如下: C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...
