【Go】Context

https://www.fengfengzhidao.com/article/WdlGxI0BEG4v2tWkq3bD#go%E8%AF%AD%E8%A8%80%E7%9A%84context
https://blog.csdn.net/weixin_52690231/article/details/124518402
https://blog.csdn.net/m0_57960197/article/details/132529334 基于源码
学一点,整一点,基本都是综合别人的,弄成我能理解的内容

Context

在 Go 语言中,Context 是一个非常重要的概念,它用于在不同的 goroutine 之间传递请求域的相关数据,并且可以用来控制 goroutine 的生命周期和取消操作。

type Context interface {Deadline() (deadline time.Time, ok bool)  //用于获取 Context 的截止时间,Done() <-chan struct{}   //用于返回一个只读的 channel,用于通知当前 Context 是否已经被取消Err() error    //用于获取 Context 取消的原因Value(key any) any  //用于获取 Context 中保存的键值对数据
}

Context使用

Background、TODO

//context/context.go
var (background = new(emptyCtx)todo       = new(emptyCtx)
)func Background() Context {return background
}func TODO() Context {return todo
}

Background函数会创建一个没有Deadline、没有Value,也不能被Cancel的emptyCtx。通常在一个请求的初始化阶段用Background()创建最顶层的根Context。

ctx := context.Background()

TODO函数和Background一样,也会创建一个emptyCtx,官方文档建议在"本来应该使用外层传递的ctx,而外层却没有传递"的地方使用,就像函数名的含义一样,留下一个TODO。

数值传递 WithValue

func main() {ctx := context.WithValue(context.Background(), "name", "fengfeng")GetUser(ctx)
}func GetUser(ctx context.Context) {// 获取用户名fmt.Println(ctx.Value("name"))
}

虽然 context.WithValue 函数允许存储任何类型的值,但是为了保证线程安全,存储的值应该是线程安全的。这意味着值本身不应该是可变的,或者应该使用互斥锁等机制来保护对它的并发访问。如果存储的值是可变的,并且可能会被多个 goroutine 同时修改,那么必须确保对这些值的访问是线程安全的。 (线程安全意味着在多线程环境下,对共享资源的访问不会引发竞态条件,能够保证数据的一致性和完整性。)

var key string="name"func main() {ctx, cancel := context.WithCancel(context.Background())// 附加值valueCtx:=context.WithValue(ctx,key,"【监控 1】")go watch(valueCtx)time.Sleep(10 * time.Second)fmt.Println("可以了, 通知监控停止")cancel()// 为了检测监控过是否停止, 如果没有监控输出, 就表示停止了time.Sleep(5 * time.Second)
}func watch(ctx context.Context) {for {select {case <-ctx.Done():// 取出值fmt.Println(ctx.Value(key),"监控退出, 停止了。..")returndefault:// 取出值fmt.Println(ctx.Value(key),"goroutine 监控中。..")time.Sleep(2 * time.Second)}}
}

取消协程 WithCancel

var wait = sync.WaitGroup{}func main() {t1 := time.Now()wait.Add(1)ctx, cancel := context.WithCancel(context.Background())go func() {ip, err := GetIp(ctx)fmt.Println(ip, err)}()wait.Add(1)go func() {time.Sleep(2 * time.Second)cancel()wait.Done()}()wait.Wait()fmt.Println("执行完成", time.Since(t1))
}func GetIp(ctx context.Context) (ip string, err error) {go func() {select {case <-ctx.Done():fmt.Println("取消", ctx.Err().Error())err = ctx.Err()wait.Done()return}}()time.Sleep(3 * time.Second)ip = "192.168.200.1"wait.Done()return
}

WithCancel函数会基于传入的parent创建一个可以Cancel的ctx,与cancel函数一起返回。调用cancel函数就会将这个新的ctx Cancel掉,所有基于此ctx创建的子孙Context也会一并被Cancel掉。

func main() {var wg sync.WaitGroupctx := context.Background()ctx1, cancel = context.WithCancel(ctx)wg.Add(1)go func() {defer wg.Done()tick := time.NewTicker(300 * time.Millisecond)for {select {case <-ctx1.Done():fmt.Println(ctx1.Err())returncase t := <-tick.C:fmt.Println(t.Nanosecond())}}}()time.Sleep(time.Second)cancel()wg.Wait()
}

截止时间 WithDeadline
除了使用 WithCancel() 方法进行取消操作之外,Context 还可以被用来设置截止时间,以便在超时的情况下取消请求

func main() {ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))go GetIp(ctx)// 5秒到了,手动结束协程time.Sleep(5 * time.Second)//cancel() // 可以手动取消,也可让他自然超时// 模拟主线程阻塞time.Sleep(1 * time.Second)}func GetIp(ctx context.Context) {fmt.Println("获取ip中")// 等待请求完成或者被取消select {case <-ctx.Done():// 请求被取消fmt.Println("请求超时或被取消", ctx.Err()) // 可以通过err判断是超时还是取消}
}

Context 使用原则

  • 不要把 Context 放在结构体中, 要以参数的方式传递
  • 以 Context 作为参数的函数方法, 应该把 Context 作为第一个参数, 放在第一位。
  • 给一个函数方法传递 Context 的时候, 不要传递 nil, 如果不知道传递什么, 就使用 context.TODO
  • Context 的 Value 相关方法应该传递必须的数据, 不要什么数据都使用这个传递
  • 保证Context 是线程安全的, 可以放心的在多个 goroutine 中传递

源码

https://blog.csdn.net/m0_57960197/article/details/132529334

cancelCtx

type cancelCtx struct {Contextmu       sync.Mutex            // protects following fieldsdone     atomic.Value          // of chan struct{}, created lazily, closed by first cancel callchildren map[canceler]struct{} // set to nil by the first cancel callerr      error                 // set to non-nil by the first cancel callcause    error                 // set to non-nil by the first cancel call
}type canceler interface {cancel(removeFromParent bool, err, cause error)Done() <-chan struct{}
}

Context:内置了一个context为父context,可见。
mu:内置了一把锁,用以协调并发场景下的资源获取
实际类型为chan struct{} 用以反映cancelCtx生命周期的通道
children:一个set指向cancelCtx的所有子context
err:记录当前cancelCtx的错误

Done

func (c *cancelCtx) Done() <-chan struct{} {d := c.done.Load()if d != nil {return d.(chan struct{})}c.mu.Lock()defer c.mu.Unlock()d = c.done.Load()if d == nil {d = make(chan struct{})c.done.Store(d)}return d.(chan struct{})
}

基于atomic包,读取cancelCtx中done chan倘若已存在则直接返回
加锁后,检查chan是否存在,存在返回 双重检查
初始化chan存储到done中返回 懒加载

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

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

相关文章

pytorch | torchvision.transforms.CenterCrop

torchvision.transforms.CenterCrop&#xff1e;从图像中心裁剪图片 transforms.CenterCrop torchvision.transforms.CenterCrop(size) 功能&#xff1a;从图像中心裁剪图片 size: 所需裁剪的图片尺寸 transforms.CenterCrop(196)的效果如下&#xff1a; &#xff08;也可…

蓝桥杯刷题--python-34-dp

2. 01背包问题 - AcWing题库 n,vmap(int,input().split()) dp[[0 for i in range(v1)] for i in range(n1)] for i in range(1,n1): v_,wmap(int,input().split()) for j in range(v1): dp[i][j]dp[i-1][j] if j>v_: dp[i][j]max(dp[i]…

2024年水电站大坝安全监测工作提升要点

根据《水电站大坝运行安全监督管理规定》&#xff08;国家发改委令第23号&#xff09;和《水电站大坝运行安全信息报送办法》&#xff08;国能安全〔2016〕261号&#xff09;的相关规定、要求&#xff0c;电力企业应当在汛期向我中心报送每日大坝汛情。近期&#xff0c;全国各地…

uniapp实现u-datetime-picker时间选择器的默认日期定位,解决default-value不生效问题

uniapp实现u-datetime-picker&#xff0c;设置默认定位日期&#xff0c;解决default-value不生效问题 想实现的效果是点开时间选择器默认显示当前日期&#xff0c;而不是该选择器最早的日期 给选择器添加ref属性&#xff0c;如下&#xff1a; <u-datetime-picker :show&q…

HarmonyOS-如何使用ArkTS声明式语法和基础组件,实现待办列表。

介绍 本篇Codelab将介绍如何使用ArkTS声明式语法和基础组件&#xff0c;实现简易待办列表。效果为点击某一事项&#xff0c;替换标签图片、虚化文字。效果如图所示&#xff1a; 相关概念 ArkTS语法&#xff1a;ArkTS是HarmonyOS的主要应用开发语言。ArkTS基于TypeScript&…

Java八股文(高并发,分布式,JUC)

Java八股文の高并发&#xff0c;分布式&#xff0c;JUC 高并发&#xff0c;分布式&#xff0c;JUC 高并发&#xff0c;分布式&#xff0c;JUC 对于高并发的系统&#xff0c;为了提高用户的体验&#xff0c;你是如何做的&#xff1f;或者说高并发的技巧你用过哪些&#xff1f; …

视频实时行为检测——基于yolov5+deepsort+slowfast算法

1. 背景介绍 随着互联网和移动设备的普及&#xff0c;视频数据量呈爆炸式增长。视频监控、智能家居、自动驾驶等领域对视频内容的理解和分析提出了更高的要求。实时行为检测技术能够从视频中识别出特定行为&#xff0c;为这些领域提供智能化的解决方案。本文将介绍一种基于yol…

Flink学习(一)-flink 本地部署

1&#xff0c;安装 jdk 官网推荐 jdk11 版本。我用 17也可以跑起来 2&#xff0c;下载 flink-1.19 的版本并解压 下载 release 1.19.0 并解压。 tar -xzf flink-1.19.0-bin-scala_2.12.tgz cd flink-1.19.0 3&#xff0c;启动 ./bin/start-cluster.sh 4&#xff0c;访问…

springboot通过threadLocal+参数解析器实现保存当前用户登录信息

首先先介绍一下threadLocal ThreadLocal 线程局部变量&#xff0c;创建一个线程变量后&#xff0c;针对这个变量可以让每个线程拥有自己的变量副本&#xff0c;每个线程是访问的自己的副本&#xff0c;与其他线程的相互独立。 大致知道threadLocal就可以了&#xff0c;然后我…

家电维修之 电子元件 学习

上面一个三角形 下面一根横线是什么电子元件 上面一个三角形下面一根横线是电子元件的图形通常表示一个二极管。二极管是一种常见的电子元件&#xff0c;它具有两个电极&#xff0c;即正极&#xff08;阳极&#xff09;和负极&#xff08;阴极&#xff09;。 上面的三角形表示…

Qt 完成图片的缩放拖动

1. 事件和函数 主要使用事件paintEvent(QPaintEvent *event)和drawTiledPixmap函数实现绘图。 paintEvent事件在改变窗口大小、移动窗口、手动调用update等情形下会被调用。需先了解下绘图该函数的用法。 - QPainter::drawTiledPixmap(int x, int y, int w, int h, const QPi…

Docker部署MongoDB+整合Mongo版MyBatis—Plus

&#x1f469;&#x1f3fd;‍&#x1f4bb;个人主页&#xff1a;阿木木AEcru &#x1f525; 系列专栏&#xff1a;《Docker容器化部署系列》 《Java每日面筋》 &#x1f4b9;每一次技术突破&#xff0c;都是对自我能力的挑战和超越。 目录 一、 MongoDB简介1.1 适用场景1.2 应…

缓冲区溢出漏洞学习总结(漏洞原理及其利用方法)

文章目录 前言1、缓冲区溢出漏洞概述1.1、漏洞概述1.2、缓冲区溢出漏洞概述1.3、缓冲区溢出攻击概述1.4、引发缓冲区溢出的原因 2、栈溢出漏洞2.1、栈溢出漏洞概述2.2、栈溢出漏洞利用2.2.1、利用方法一&#xff1a;修改返回地址2.2.2、利用方法二&#xff1a;覆盖临接变量 3、…

(js)循环条件满足时终止循环

(js)循环条件满足时终止循环 功能需求&#xff1a;勾选的字段中若包含“数据标注划分”则显示数据划分&#xff0c;不包含则不显示 包含&#xff1a; 不包含&#xff1a; // 标注划分显示 const markStr 数据标注划分 for (let i 0; i < value.length; i) { //value为勾选…

Coursera自然语言处理专项课程03:Natural Language Processing with Sequence Models笔记 Week02

Natural Language Processing with Sequence Models Course Certificate 本文是https://www.coursera.org/learn/sequence-models-in-nlp 这门课程的学习笔记&#xff0c;如有侵权&#xff0c;请联系删除。 文章目录 Natural Language Processing with Sequence ModelsWeek 02…

vsqt更改ui,cpp报错(唯二)解决方法,及ui界面布局在cpp文件的运用基本流程

qt的ui布局界面如下 点cpp文件->编译 此时就会自动生成ui_xxx.h 这里是ui文件里面就有类名&#xff1a;Ui_文件名字 下面就有一个类继承于这个类 你所使用的这个ui指针&#xff0c;就这么来的 ***报错解决方法有两种&#xff1a;***第一种&#xff1a;如果改了ui&#x…

Mac更换JDK版本

1.确保系统中存在多个Java版本。 在Terminal中执行&#xff1a; /usr/libexec/java_home -V 结果&#xff1a; Matching Java Virtual Machines (2): 11.0.1, x86_64: "Java SE 11.0.1" /Library/Java/JavaVirtualMachines/jdk-11.0.1.jdk/Contents/Home 1.8.0_2…

一道题目 加深对差分和二分的理解

[NOIP2012 提高组] 借教室 - 洛谷 差分 针对区间操作&#xff0c;在本题中体现为多次对序列的区间加上一个数 对差分数组的操作为&#xff0c; diff[l] k; diff[r1] - k; 最后通过前缀和来实现整个区间加上一个数的效果。 二分 大多数人对于二分的基础印象可能是&#xf…

Pytorch nn.Linear()

nn.Linear就是神经网络中的线性层&#xff0c;类似于数学中的线性函数&#xff0c;可以实现形如yX*weight^Tb的功能。 #导包 import torch.nn as nn import torch#创建1个张量 sampletorch.tensor([1.,10.,100.])#nn.Linear(in_feature,out_feature,bias)&#xff0c;这里设置…

钉钉服务端API报错 错误描述: robot 不存在;解决方案:请确认 robotCode 是否正确

problem 调用钉钉服务端API&#xff0c;机器人发送群聊消息&#xff0c;后台返回报错信息: 钉钉服务端API报错 错误描述: robot 不存在&#xff1b;解决方案:请确认 robotCode 是否正确&#xff1b; reason 定位: 登录后台&#xff0c;查看机器人是存在查看机器人调用权限接…