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

[Golang] Context

[Golang] Context

文章目录

  • [Golang] Context
    • 什么是context
    • 创建context
      • 创建根context
      • 创建context
    • context的作用
      • 并发控制
      • context.WithCancel
      • context.WithDeadline
      • context.WithTimeout
      • context.WithValue

什么是context

Golang在1.7版本中引入了一个标准库的接口context,定义:

type Context interface {Deadline() (deadline time.Time, ok bool)Done() <-chan struct{}Err() errorValue(key any) any
}

它定义了四个方法:

  • Deadline:设置context.Context被取消的时间,即截止日期

  • Done:返回一个只读channel,当Context到达截止日期时或被取消,这个channel就会被关闭,表示Context的链路结束,多次调用Done会返回同一个channel

  • Err:返回Context结束的原因,它只会在Done返回的channel被关闭时,才会返回非空的值;

    • 情况1:Context被取消:返回Canceled
    • 情况2:Context超时:返回DeadlineExceeded
  • Value:从context.Context中获取键对应的值,类似与map的get方法,对于同一个Context,多次调用Value并传入相同的key会返回相同的结果,如果没有对应的key就返回nil。

    • 键值对通过WithValue方法写入
func WithValue(parent Context, key, val any) Context {if parent == nil {panic("cannot create context from nil parent")}if key == nil {panic("nil key")}if !reflectlite.TypeOf(key).Comparable() {panic("key is not comparable")}return &valueCtx{parent, key, val}
}

创建context

创建根context

两种方法:

  • context.Background()
  • context.TODO()

两者没有什么太多的区别,都是创建根context,根context是一个空的context,不具备任何功能。

一般情况下,当前函数没有上下文作为入参,我们就使用context.Background()创建一个根context作为起始的上下文向下传递。

创建context

根context被创建后,不具备任何功能,为了让context在程序中发挥作用,我们需要依靠包提供的With系列函数来进行派生。

四个派生函数:

func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {...}
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) {...}
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {...}
func WithValue(parent Context, key, val any) Context {...}

基于当前context,每个With函数都会创建出一个新的context,这类似于我们熟悉的树结构,当前context称为父context,派生出的每个新context被称为子context。

image-20240918180659297

通过根context的四个With函数派生出四种类型的context,每种context又可以通过同样的方式调用with系列方法继续向下派生出新的context,整体结构像一个树一样。

context的作用

  • 用于并发控制,控制协程的退出
  • 上下文信息的传递

总的来说,就是用来在父子goroutine间进行值传递和发生cancel信号的一种机制。

并发控制

一般的服务器都是一直运行的,等待客户端或者浏览器的请求做出响应,思考这种场景,一个微服务架构中下,服务器收到一个请求后,并不会在一个goroutine下完成(如果逻辑复杂),而是创建很多goroutine共同完成这个请求。

假设有rpc1—rpc2—rpc3—rpc4—rpc5,5个rpc调用。

但是如果在整个rpc调用中,如果rpc1就出现了错误,如果没有context存在,服务器就会坚持调用完整个流程,也就是等待所有rpc调用完成后才能返回结果,但是实际上这样浪费了不少的时间,单纯浪费计算和IO资源(rpc1错误之后的rpc调用都是无用功)。因为rpc调用之间不知道已经产生了错误,而context就很好的解决了这个问题。

在不需要子goroutine继续执行的时候,通过context通知子goroutine关闭即可。

context.WithCancel

func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {c := withCancel(parent)return c, func() { c.cancel(true, Canceled, nil) }
}

context.WithCancel函数是一个取消控制函数,只需要一个context作为参数,能够衍生出一个新的子context和取消函数Cancel,我们可以通过这个将这个子context传入子goroutine中,执行Cancel函数来关闭这个子goroutine,当前的上下文和它的子上下文都会被取消,所有的goroutine都会同步收到取消信号。

示例:

package mainimport ("context""fmt""time"
)func main() {fmt.Println()ctx, cancel := context.WithCancel(context.Background())go watch(ctx, "goroutine1")go watch(ctx, "goroutine2")time.Sleep(3 * time.Second)fmt.Println("end!!!")cancel()time.Sleep(time.Second)
}
func watch(ctx context.Context, name string) {for {select {case <-ctx.Done():fmt.Println(name, " exit")returndefault:fmt.Println(name, " watching")time.Sleep(time.Second)}}
}

执行结果:

image-20240918184141136

通过WithCancel函数派生出一个带有返回函数cancel的ctx:ctx, cancel := context.WithCancel(context.Background()),并且把ctx传入子goroutine中,在3秒内没有执行cancel,子goroutine将一直执行default语句,3秒后,执行cancel,此时子goroutine从ctx.Done()收到消息,执行return结束。

context.WithDeadline

func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) {return WithDeadlineCause(parent, d, nil)
}

context.WithDeadline函数也是一个取消控制函数,共有两个参数,一个是context,另一个是截止时间,同样会返回一个子context和取消函数cancel。在使用时,如果没有到截止日期,我们可以通过调用cancel函数来手动取消context,控制goroutine的退出,如果到了截止日期,我们都没有调用cancel函数,子context的Done()管道也会收到一个取消信号,来控制子goroutine的退出。

示例:

package mainimport ("context""fmt""time"
)func main() {fmt.Println()ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(3*time.Second))defer cancel()go watch(ctx, "goroutine1")go watch(ctx, "goroutine2")// 让goroutine1和goroutine2先执行5秒time.Sleep(5 * time.Second)fmt.Println("end!!!")}
func watch(ctx context.Context, name string) {for {select {case <-ctx.Done()://但是不到5秒,3秒时收到了退出信号fmt.Println(name, " exit")returndefault:fmt.Println(name, " watching")time.Sleep(time.Second)}}
}

执行结果:

image-20240918210655210

我们并没有调用cancel函数,但是在过了3秒后,子goroutine里ctx.Done()收到了信号,子goroutine进行退出。

context.WithTimeout

func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {return WithDeadline(parent, time.Now().Add(timeout))
}

context.WithTimeoutcontext.WithDeadline差不多,都是用于超时取消子context,只是第二个参数有点区别,不是具体时间,而是时间长度。

示例:

package mainimport ("context""fmt""time"
)func main() {fmt.Println()ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)defer cancel()go watch(ctx, "goroutine1")go watch(ctx, "goroutine2")// 让goroutine1和goroutine2先执行5秒time.Sleep(5 * time.Second)fmt.Println("end!!!")}
func watch(ctx context.Context, name string) {for {select {case <-ctx.Done()://但是不到5秒,3秒时收到了退出信号fmt.Println(name, " exit")returndefault:fmt.Println(name, " watching")time.Sleep(time.Second)}}
}

执行结果:

image-20240918211051169

执行结果和context.WithDeadline类似。

context.WithValue

func WithValue(parent Context, key, val any) Context {if parent == nil {panic("cannot create context from nil parent")}if key == nil {panic("nil key")}if !reflectlite.TypeOf(key).Comparable() {panic("key is not comparable")}return &valueCtx{parent, key, val}
}

context.WithValue函数从父context中创建一个子context用于传值,函数参数是父context、key、val,返回一个context。一般用于上下文信息的传递,比如请求唯一id,以及trace_id,用于链路追踪以及配置穿透。

示例:

package mainimport ("context""fmt""time"
)func main() {fmt.Println()ctx := context.WithValue(context.Background(), "name", "张三")go func1(ctx)time.Sleep(time.Second)
}
func func1(ctx context.Context) {fmt.Println("name = ", ctx.Value("name").(string))
}

执行结果:

image-20240918211613966

相关文章:

[Golang] Context

[Golang] Context 文章目录 [Golang] Context什么是context创建context创建根context创建context context的作用并发控制context.WithCancelcontext.WithDeadlinecontext.WithTimeoutcontext.WithValue 什么是context Golang在1.7版本中引入了一个标准库的接口context&#xf…...

【JAVA集合总结-壹】

文章目录 synchronized 的实现原理以及锁优化&#xff1f;ThreadLocal原理&#xff0c;使用注意点&#xff0c;应用场景有哪些&#xff1f;synchronized和ReentrantLock的区别&#xff1f;说说CountDownLatch与CyclicBarrier 区别Fork/Join框架的理解为什么我们调用start()方法…...

Mysql梳理7——分页查询

目录 7、分页查询 7.1 背景 7.2 实现规则 分页原理 7.3 使用 LIMIT 的好处 7、分页查询 7.1 背景 背景1&#xff1a;查询返回的记录太多了&#xff0c;查看起来很不方便&#xff0c;怎么样能够实现分页查询呢&#xff1f; 背景2&#xff1a;表里有 4 条数据&#xff0c…...

智能制造与工业互联网公益联播∣企企通副总经理杨华:AI的浪潮下,未来智慧供应链迭代方向

近两年在IT圈子里面&#xff0c;AI毫无疑问是最火的一个词语&#xff0c;最近的ChatGPT、文心一言、通义千问&#xff0c;从千亿参数到万亿参数&#xff0c;再往前就是Sora文生视频异军突起... 在人工智能的浪潮下&#xff0c;AI之于供应链的价值体现在哪些地方&#xff1f;其发…...

《深度学习》—— 卷积神经网络(CNN)的简单介绍和工作原理

文章目录 一、卷积神经网络的简单介绍二、工作原理(还未写完)1.输入层2.卷积层3.池化层4.全连接层5.输出层 一、卷积神经网络的简单介绍 基本概念 定义&#xff1a;卷积神经网络是一种深度学习模型&#xff0c;通常用于图像、视频、语音等信号数据的分类和识别任务。其核心思想…...

数据结构:线性表

1、线性表概述 1.1线性表的定义 线性表&#xff08;list&#xff09;&#xff1a;零个或多个数据元素的有限序列。 简单地来说&#xff0c;我们可以用下面这张图来描述一个线性表&#xff1a; 1.2 线性表的存储结构 1.2.1顺序存储结构——顺序表 顺序表是将数据全部存储到…...

Ansible PlayBook实践案例

一、PlayBook介绍 1.什么是playbook playbook 顾名思义&#xff0c;即剧本&#xff0c;现实生活中演员按照剧本表演&#xff0c;在 ansible 中&#xff0c;由被控计算机表演,进行安装&#xff0c;部署应用&#xff0c;提供对外的服务等&#xff0c;以及组织计算机处理各种各样…...

Tomcat后台弱口令部署war包

1.环境搭建 cd /vulhub/tomcat/tomcat8 docker-compose up -d 一键启动容器 2.访问靶场 点击Manager App tomcat8的默认用户名和密码都是tomcat进行登录 3.制作war包 先写一个js的一句话木马 然后压缩成zip压缩包 最后修改后缀名为war 4.在网站后台上传war文件 上传war文件…...

胤娲科技:DeepMind的FermiNet——带你穿越“薛定谔的早餐桌”

当AI遇上量子迷雾&#xff0c;FermiNet成了你的“量子导航仪” 想象一下&#xff0c;你早晨醒来&#xff0c;发现家里的厨房变成了薛定谔的实验室&#xff0c;你的咖啡杯和吐司同时处于“存在与不存在”的叠加态。 你伸手去拿&#xff0c;却不确定会不会摸到冰冷的空气或是热腾…...

迅为iTOP-STM32MP157开发板板载4G接口(选配)_千兆以太网_WIFI蓝牙模块_HDMI_CAN_RS485_LVDS接口等

迅为ITOP-STM32MP157是基于ST的STM32MP157芯片开发的一款开发平台。在STM32MP157开发平台上&#xff0c;我们也做了比较多的创新&#xff0c;其中重要的一点就是&#xff0c;iTOP-STM32MP157核心板电源管理采用ST全新配套研制的PMIC电源管理芯片STPMU1A。为整个系统的稳定运行提…...

Android Choreographer 监控应用 FPS

Choreographer 是 Android 提供的一个强大的工具类&#xff0c;用于协调动画、绘制和视图更新的时间。它的主要作用是协调应用的绘制过程&#xff0c;以确保流畅的用户体验。Choreographer 也可以帮助我们获取帧时间信息&#xff0c;从而为性能监测和优化提供重要的数据支持。 …...

关于 mybatis-plus-boot-starter 与 mybatis-spring-boot-starter 的错误

不是知道你是否 出现过这样的错误 org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): 经过各种度娘&#xff0c;无非就是让你检查三种情况 情况一&#xff1a;mapper.xml没有按照传统的maven架构进行放置 情况二&#xff1a;mybatis的配置信…...

NLP 文本分类任务核心梳理

解决思路 分解为多个独立二分类任务将多标签分类转化为多分类问题更换 loss 直接由模型进行多标签分类 数据稀疏问题 标注更多数据&#xff0c;核心解决方案&#xff1a; 自己构造训练样本 数据增强&#xff0c;如使用 chatGPT 来构造数据更换模型 减少数据需求增加规则弥补…...

k8s中pod的创建过程和阶段状态

管理k8s集群 kubectl k8s中有两种用户 一种是登录的 一种是/sbin/nologin linux可以用密码登录&#xff0c;也可以用证书登录 k8s只能用证书登录 谁拿到这个证书&#xff0c;谁就可以管理集群 在k8s中&#xff0c;所有节点都被网络组件calico设置了路由和通信 所以pod的ip是可以…...

NSSCTF刷题篇1

js类型 [SWPUCTF 2022 新生赛]js_sign 这是一道js信息泄露的题目直接查看源码&#xff0c;有一个main.js文件点击之后&#xff0c;有一串数字和一段base64编码&#xff0c;解开base64编码得到这个编码为敲击码 解码在线网站&#xff1a;Tap Code - 许愿星 (wishingstarmoye.…...

[数据集][目标检测]棉花叶子病害检测数据集VOC+YOLO格式977张22类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;977 标注数量(xml文件个数)&#xff1a;977 标注数量(txt文件个数)&#xff1a;977 标注类别…...

产品经理面试整理-常见面试问题

以下是一些常见的产品经理面试问题及其解答思路。这些问题涵盖了产品管理的各个方面,包括战略、执行、数据分析、用户体验、跨团队合作等。在准备这些问题时,使用结构化的回答方式(如STAR法)能够帮助你更好地表达你的观点和经验。 1. 常见产品经理面试问题 1.1 你如何定义用…...

数据库(选择题)

基本概念 数据库&#xff08;DB&#xff09;&#xff1a;长期存储在计算机内的、有组织的、可共享的数据集合。 数据库管理系统&#xff08;DBMS&#xff09;&#xff1a;它是数据库的机构&#xff0c;是一个系统软件&#xff0c;负责数据库中的数据组织、数据操纵、数据维护…...

粒子向上持续瀑布动画效果(直接粘贴到记事本改html即可)

代码&#xff1a; 根据个人喜好修改即可 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>宽粒子向上…...

卷积神经网络(CNN):深度学习中的视觉奇迹

目录 一、什么是卷积神经网络&#xff1f; 二、CNN的核心组件 1. 卷积层&#xff08;Convolutional Layer&#xff09; 2. 激活函数&#xff08;Activation Function&#xff09; 3. 池化层&#xff08;Pooling Layer&#xff09; 4. 全连接层&#xff08;Fully Connected…...

如何突破Switch游戏限制:Ryujinx开源模拟器的5大实战解决方案

如何突破Switch游戏限制&#xff1a;Ryujinx开源模拟器的5大实战解决方案 【免费下载链接】Ryujinx 用 C# 编写的实验性 Nintendo Switch 模拟器 项目地址: https://gitcode.com/GitHub_Trending/ry/Ryujinx 你是否渴望在PC上畅玩Switch独占游戏&#xff0c;却受限于硬件…...

HarmonyOS APP<<古今职鉴定>>开源教程第20篇:农历日期与节日计算

本篇学习农历算法&#xff0c;实现年俗内容的日期驱动图&#xff1a;农历日期与节日计算 的关键流程与实现要点。 学习目标 完成本篇后&#xff0c;你将能够&#xff1a; ✅ 理解农历算法原理✅ 实现公历转农历✅ 计算传统节日✅ 实现年俗日期匹配 预计学习时间 约 90 分钟…...

获 800 万美元融资,MAU 超 40 万!「shapes」AI 社交能否成下一代聊天应用?

《「shapes」获 800 万美元种子轮融资&#xff0c;AI 助力社交“入场”&#xff0c;能否成下一代聊天应用&#xff1f;》这几天&#xff0c;我在「shapes」随机进了个陌生群聊&#xff0c;发了句 "hello"&#xff0c;三秒内就有 AI 角色接上&#xff0c;回了串热情有…...

Rust 核心理论: 高并发与异步(三)

写在前面 Rust 凭借其独特的所有权机制和借用检查器&#xff0c;在不依赖垃圾回收的前提下&#xff0c;实现了内存安全与线程安全的编译期保证。 然而&#xff0c;对于许多从 C/C、Java、Python 等背景转入 Rust 的开发者而言&#xff0c;所有权、生命周期、借用规则、内部可变…...

社保照片怎么手机搞定?社保照片要求有哪些?2026手机拍摄社保照片完整指南

社保办理、医保激活、养老金申请……这些民生相关的事务都离不开一张正式的证件照。很多人以为必须去照相馆花钱拍摄&#xff0c;但其实用手机就能完全搞定。无论是首次办理社保还是证件过期更新&#xff0c;这篇教程都能帮你省时省钱&#xff0c;拍出符合社保部门要求的标准照…...

Taotoken审计日志功能在满足企业合规与安全需求中的作用观察

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 Taotoken审计日志功能在满足企业合规与安全需求中的作用观察 1. 引言&#xff1a;企业API治理中的可观测性挑战 在企业技术架构中…...

yolo11红外光伏板图像识别 光伏板缺陷检测系统

YOLOv11光伏板热缺陷检测系统是一种利用先进的YOLOv11算法进行太阳能光伏板缺陷识别的解决方案。这种系统通常会包含以下几个关键部分&#xff1a; 安装教程 1.安装minconda 2.pycharm 3.安装cuda&#xff08;11.0&#xff09;&#xff08;下载链接&#xff1a;https://develop…...

别再只写CRUD了!用SpringBoot+MySQL设计一个高并发预约挂号系统,这些架构细节你得知道

高并发预约挂号系统架构实战&#xff1a;SpringBootMySQL核心技术解析 1. 系统架构设计挑战与解决方案 在医疗信息化高速发展的今天&#xff0c;预约挂号系统作为医院服务的"第一窗口"&#xff0c;其稳定性与性能直接影响患者就医体验。传统CRUD架构在面对挂号早高峰…...

openpilot深度解析:开源驾驶辅助系统的技术实现与架构设计

openpilot深度解析&#xff1a;开源驾驶辅助系统的技术实现与架构设计 【免费下载链接】openpilot openpilot is an operating system for robotics. Currently, it upgrades the driver assistance system on 300 supported cars. 项目地址: https://gitcode.com/GitHub_Tre…...

光电效应实验避坑指南:从汞灯预热到遏止电压判读,新手常犯的5个错误

光电效应实验避坑指南&#xff1a;从汞灯预热到遏止电压判读的5个关键误区 在大学的物理实验室里&#xff0c;光电效应实验就像一位性格古怪的教授——看似简单明了&#xff0c;实则暗藏玄机。许多同学满怀信心地走进实验室&#xff0c;却在数据采集阶段屡屡碰壁&#xff0c;最…...