go语言并发编程(五) ——Context

Context(上下文)

前言

Context是go语言中所提供的一种并发控制的解决方案,相比于管道与WaitGroup,Context可以更好的控制子孙协程以及层次更深的协程。Context本身是一个接口,只要我们实现了该接口都可以被称为上下文,context标准库本身也提供了几个实现:

  • emptyCtx
  • cancelCtx
  • timerCtx
  • valueCtx

什么是Context

在看Context的具体实现之前,先来看看Context接口的定义.

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

我们来看一看这个接口里面所定义的四个方法:

  • Deadline
    该方法有两个返回值,deadline是截止时间,也就是上下文截止的时间,第二个值是是否设置dedline,如果没有则一直为false.
  • Done
    返回值是一个空结构体的只读管道,该管道仅仅起到通知作用,不传递任何数据,当上下文所做的工作要取消的时候,该通道就会被关闭,对于一些不支持取消的上下文,可能会返回nil
  • Err
    该方法会返回一个error,用来表示上下关闭的原因,如果管道没有关闭,则返回nil,如果关闭的话,则返回一个error,用来表示上下文关闭的原因。
  • Value
    该方法返回对应的键值,如果key不存在,或者不支持该方法,就会返回nil。

下面我们来看一个简单的例子:

package mainimport ("context""fmt""sync""time"
)var wa sync.WaitGroup
var stop bool
var RW sync.RWMutexfunc cpuIInfo(ctx context.Context) {defer wa.Done()for {select {case <-ctx.Done():fmt.Println("cpu info exit")returndefault:time.Sleep(2 * time.Second)fmt.Println("cpu info")}}
}func main() {wa.Add(1)ctx, cancel := context.WithCancel(context.Background())go cpuIInfo(ctx)time.Sleep(6 * time.Second)cancel()fmt.Println("main exit")wa.Wait()
}

输出为:

cpu info
cpu info
main exit
cpu info
cpu info exit

或许现在你不是很清楚上面的例子,但是看完今天的博文以后,相信大家就能和好的理解了话不多说,让我们来看一下有关context的具体内容:

emptyCtx

顾名思义,emptyCtx指的就是空的上下文,context包下所有的实现其实都是不对外暴露的,所以我们无法直接创建context.Context,但是go语言提供了对应的函数区创建上下文,例如下面我们可以利用context.Background()context.TODO()函数来创建一个空的上下文:两个函数的具体实现如下:

var{background =new(emptyCtx)todo =new(emptyCtx)
}func Background()Context{return background
}func TODO()Context{return todo
}

我们再来看看emptyCtx四个函数的实现:

type  emptyCtx intfunc (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
return
}func () Done() <-chan struct{} {
return nil
}func () Value(key any) any {
return nil
}func (emptyContext) Err() error {
return nil
}

我们仔细观察emptyCtx的实现,发现其实emptyCtx仅仅返回了emptyCtx指针.emptyCtx的底层类型是int,之所以不使用空结构体,在之前我们提到过空结构体没有字段,不占用内存,但是我们要求emptyCtx的实例都要有自己的内存地址,而在它的方法中,由于它不能被取消,所以它没有deadline,由于它不能被取值,所以它实现的方法都是返回nil.emptyCtx通常是用来当作最顶层的上下文,在创建其他三种上下文时作为父上下文传入。

valueCtx

valueCtx的实现比较简单,它的内部只包括一对键值对,和一个内嵌的Context字段:

type valueCtx struct{Contextkay,value any
}

它自身也实现了Value方法,基本逻辑其实也很简单:找不到就去喊爸爸(去父上下文找):

func (c *valueCtx) Value(key any) any{if c.key==key{return c}return value(c.Context,key)
}

我们可以来看一个简单的例子:

package mainimport ("context""sync""time"
)var w sync.WaitGroupfunc main() {w.Add(1)go Do(context.WithValue(context.Background(), 1, 2))w.Wait()
}func Do(ctx context.Context) {ticker := time.NewTimer(2 * time.Second)defer w.Done()for {select {case <-ticker.C:println("time out")returncase <-ctx.Done():default:println(ctx.Value(1).(int))}time.Sleep(100 * time.Millisecond)}
}

输出为:

2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
time out

valueCtx多用于在多级协程中传递一些数据,无法被取消,因此ctx.Done永远会返回nil,select会忽略掉nil管道。

cancelCtx

cancelCtx以及timerCtx都实现了canceler接口,接口类型如下:

type canceler interface {// removeFromParent 表示是否从父上下文中删除自身// err 表示取消的原因cancel(removeFromParent bool, err, cause error)// Done 返回一个管道,用于通知取消的原因Done() <-chan struct{}
}

我们查看上面的源码可以看出来:cancel方法本身不对外暴露,但是会在我们创建上下文的时候通过闭包来将其封装成返回值供外界调用,这个在源码中也有所体现:

func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {if parent==nil{panic("cannot create context from nil parent")}c:=newCancelCtx(parent)//尝试将自身添加进父级的children中propagateCancel(parent,&c)return &c,func(){c.cancel(true,context.Canceled,nil)}
}

cancelCtx我们可以理解为一个可取消的上下文,它在创建的时候如果父级实现了canceler,就会将自身添加进父级的children中,否则就一直向上查找。如果所有的父级都没有实现canceler,就会启动一个协程等待父级取消,然后当父级结束时取消当前上下文。当调用cancelFunc时,Done通道将会关闭,该上下文的任何子级也会随之取消,最后会将自身从父级中删除。下面我们来看个例子:

package mainimport ("context""fmt""sync""time"
)var w sync.WaitGroupfunc main() {bkg := context.Background()ctx, cancel := context.WithCancel(bkg)w.Add(1)go func(ctx2 context.Context) {defer w.Done()for {select {case <-ctx.Done():fmt.Println(ctx.Err())returndefault:fmt.Println("等待取消中...")}time.Sleep(time.Millisecond * 200)}}(ctx)time.Sleep(time.Second * 3)cancel()w.Wait()
}

输出为:

等待取消中...
等待取消中...
等待取消中...
等待取消中...
等待取消中...
等待取消中...
等待取消中...
等待取消中...
等待取消中...
等待取消中...
等待取消中...
等待取消中...
等待取消中...
等待取消中...
等待取消中...
context canceled

timerCtx

相对于cancelCtx,timerCtx多了超时机制,context包下提供了两种创建的函数:

func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)

这两个函数的功能类似,前者是指定一个具体的时间而后者则是指定一个时间间隔。timeCtx会在时间到期后自动取消上下文,取消的流程除了要额外的关闭timer之外,基本与cancelCtx一致,我们来看一个简单的示例:

package mainimport ("context""fmt""sync""time"
)var w sync.WaitGroupfunc main() {w.Add(1)deadline, ctx := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))defer ctx()go func(ctx2 context.Context) {defer w.Done()for {select {case <-deadline.Done():fmt.Println("上下文取消")returndefault:fmt.Println("等待取消")}time.Sleep(1 * time.Second)}}(deadline)w.Wait()
}

WithTimeout其实与WithDealine非常相似,它的实现也只是稍微封装了一下并调用WithDeadline,和上面例子中的WithDeadline用法一样,如下:

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

注意:
就跟内存分配后不回收会造成内存泄漏一样,上下文也是一种资源,如果创建了但从来不取消,一样会造成上下文泄露,所以最好避免此种情况的发生。

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

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

相关文章

移动端web适配方案

以下是移动端适配的多个方案&#xff0c;也可以说说你是怎么做的。 正文 自适应&#xff1a;根据不同的设备屏幕大小来自动调整尺寸、大小 响应式&#xff1a;会随着屏幕的实时变动而自动调整&#xff0c;是一种更强的自适应 为什么要做移动端适配&#xff1f; 目前市面上…

Linux内核与基础命令学习总结

Linux操作系统 Linux操作系统博大精深&#xff0c;其中对线程&#xff0c;IO&#xff0c;文件系统等概念的实现都很有借鉴意义。 ​ 文件系统和VFS 文件系统的inode上面讲过了。VFS主要用于屏蔽底层的不同文件系统&#xff0c;比如接入网络中的nfs文件系统&#xff0c;亦或是w…

如何使用docker-compose安装数据可视化应用JSON Crack并实现远程访问

文章目录 1. 在Linux上使用Docker安装JSONCrack2. 安装Cpolar内网穿透工具3. 配置JSON Crack界面公网地址4. 远程访问 JSONCrack 界面5. 固定 JSONCrack公网地址 JSON Crack 是一款免费的开源数据可视化应用程序&#xff0c;能够将 JSON、YAML、XML、CSV 等数据格式可视化为交互…

SAP SD学习笔记08 - Pre-sales(售前)引合,見積的概念,数据流(完了规则和参照Status),Copy管理,VBKD表的明细

上一章讲了紧急发注&#xff0c;现金贩卖&#xff0c;贩卖传票&#xff0c;明细Category等知识。 SAP SD学习笔记07 - 紧急发注&#xff08;急单&#xff09;&#xff0c;现金贩卖&#xff0c;贩卖传票Type/ 明细Category 及其Customize-CSDN博客 - 本张继续讲SAP SD模块的流程…

青铜器RDM研发管理平台 upload 任意文件上传漏洞复现

0x01 产品简介 青铜器RDM研发管理平台是集成产品管理、研发部门管理、研发项目管理、研发多项目管理、研发资源管理、研发绩效管理、研发工程管理的集中平台。 0x02 漏洞概述 青铜器RDM研发管理平台 upload 接口存在任意文件上传漏洞,未经身份验证的远程攻击者可通过该漏洞…

【板栗糖GIS】如何给微软拼音输入法加上小鹤双拼

【板栗糖GIS】如何给微软拼音输入法加上小鹤双拼 用过在注册表里新建的方法&#xff0c;结果弄完没有出现小鹤双拼方案&#xff0c;想到了自己写reg表 目录 1. 新建一个txt文件 2. 把.txt的后缀名改成.reg&#xff0c;双击运行 3. 在设置中找到微软输入法-常规 1. 新建一个…

微信预约怎么做_体验便捷的服务

在这个快节奏的时代&#xff0c;时间显得格外珍贵。无论是工作还是生活&#xff0c;我们都渴望能够用最短的时间完成更多的事情。在这样的背景下&#xff0c;微信预约应运而生&#xff0c;成为我们追求高效、便捷生活的新宠。今天&#xff0c;就让我们一起探讨微信预约的魅力&a…

相机系列——透视投影:针孔相机模型

作者&#xff1a;木一 引言 上文我们提到&#xff0c;三维相机是对真实世界成像的模拟&#xff0c;为了让三维物体在计算机屏幕上呈现出来的图像符合人眼观察效果&#xff0c;通常采用透视投影方式模拟相机成像&#xff0c;为了简化计算&#xff0c;可以用针孔相机模型来描述…

麒麟服务器操作系统安装HTTP服务

往期好文&#xff1a;麒麟服务器操作系统安装TFTP服务 Hello&#xff0c;大家好啊&#xff01;今天我们将探讨如何在麒麟服务器操作系统上安装和配置HTTP服务&#xff0c;这是任何网络服务或应用的基础。无论你是想建立一个简单的网站&#xff0c;还是需要一个全功能的Web服务器…

CodeMirror使用: 编写一个在线编辑HTML、JS、CSS文件,网页的模板页面-初实现

前言&#xff1a;前几天编写一个UI模板控制的功能&#xff0c;根据上传的前端模板更换跳转入口主题页面&#xff1b;在编写的时候&#xff0c;突发奇想能不能在列表页面进行在线编辑刚刚上传的模板zip压缩包里的页面...于是经过学习研究有了这篇文章&#xff1b;当日记本一样记…

图灵《模仿游戏》论文学习

文章目录 1. 写在最前面2. 核心观点学习2.1 脑图观点记录2.2 经典观点记录 3. 感受4. 碎碎念5. 参考资料 1. 写在最前面 3 月看了一部以图灵为原型拍摄的人物传记类电影《模仿游戏》&#xff0c;里面反复提及到的论文《COMPUTING MACHINERY AND INTELLIGENCE》&#xff0c;引起…

计算机丢失VCRUNTIME140_1.dll处理办法

一、打开 下面连接地址&#xff0c;下载Visual Studio 2015, 2017, 2019, and 2022 https://learn.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?viewmsvc-170#visual-studio-2015-2017-2019-and-2022 二、下载系统对应的版本 32位系统下载X86 64位系统下载X…

win10 鼠标箭头自己乱动解决方案

我这里只说我碰到的然后我的解决方案&#xff0c;不一定对其他问题有效&#xff1b; 1. 首先拔掉鼠标线查看鼠标箭头是否仍然在乱动&#xff0c;如果是则非鼠标问题&#xff0c;如果不再乱动则是鼠标的问题&#xff1b;验证非鼠标问题&#xff1b; 2. 因为鼠标乱动跟鼠标无关…

【深度学习】AI修图——DragGAN原理解析

1、前言 上一篇&#xff0c;我们讲述了StyleGAN2。这一篇&#xff0c;我们就来讲一个把StyleGAN2作为基底架构的DragGAN。DragGAN的作用主要是对图片进行编辑&#xff0c;说厉害点&#xff0c;可能和AI修图差不多。这篇论文比较新&#xff0c;发表自2023年 原论文&#xff1a…

韩顺平 | 零基础快速学Python(16) 文件处理

文件 输入与输出 输入&#xff1a;数据从数据源(文件)到程序(内存)&#xff1b; 输出&#xff1a;数据从程序(内存)到数据源(文件)。 #mermaid-svg-06PG6JZq4jJMV1oH {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-sv…

数据库查询:查询入参类型和数据库字段类型不匹配导致的问题

问题&#xff1a;假设我们现在有这样的一张表 CREATE TABLE test_person (id int(20) NOT NULL COMMENT 主键,name varchar(20) DEFAULT NULL COMMENT 姓名,gender char(2) DEFAULT NULL COMMENT 性别,birthday date DEFAULT NULL COMMENT 生日,created_time timestamp NULL D…

JS-33-jQuery02-选择器

一、单个选择器 选择器是jQuery的核心。 一个选择器写出来类似$(#dom-id)。 美元符号定义 jQuery 为什么jQuery要发明选择器&#xff1f;回顾一下DOM操作中我们经常使用的代码&#xff1a; // 按ID查找&#xff1a; var a document.getElementById(dom-id);// 按tag查找&am…

Java的maven项目导入本地jar包的三种方式

文章目录 Java的maven项目导入本地jar包的三种方式1、在项目中创建一个lib文件夹&#xff0c;将想要使用的本地jar包放进去2、方法一&#xff1a;直接在pom.xml中添加下列依赖&#xff08;项目协作推荐&#xff09;3、方法二&#xff1a;在项目结构中引用lib文件夹&#xff08;…

ATA-2048高压放大器在铁电材料中有什么应用

铁电材料是一类具有特殊电学性质的材料&#xff0c;它们能够在外加电场的作用下产生可逆的电极化&#xff0c;这种电极化可以在没有外加电场时保持。这使得铁电材料在许多应用中具有重要价值&#xff0c;特别是在电子设备和传感器领域。高压放大器作为一种电子设备&#xff0c;…

C++:Hash应用【位图与布隆过滤器】

什么是位图&#xff1f; 我们先来看一个问题&#xff1a; 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&#xff0c;如何快速判断一个数是否在 这40亿个数中。【腾讯】 如果我们使用unordered_set容器来解决&#xff0c;40亿个数据&#xff0c;每个数据…