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

go语言-context的基本使用

1. 什么是 Context?

Go 1.7 标准库引入 context,中文译作“上下文”,准确说它是 goroutine 的上下文,包含 goroutine 的运行状态、环境、现场等信息。

context 主要用来在 goroutine 之间传递上下文信息,包括:取消信号、超时时间、截止时间、k-v 等。

Context,也叫上下文,它的接口定义如下

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

可以看到 Context 接口共有 4 个方法

  • Deadline:返回的第一个值是截止时间,到了这个时间点,Context 会自动触发 Cancel 动作。返回的第二个值是 一个布尔值,true 表示设置了截止时间,false 表示没有设置截止时间,如果没有设置截止时间,就要手动调用 cancel 函数取消 Context。

  • Done:返回一个只读的通道(只有在被cancel后才会返回),类型为 struct{}。当这个通道可读时,意味着parent context已经发起了取消请求,根据这个信号,开发者就可以做一些清理动作,退出goroutine。

  • Err:返回 context 被 cancel 的原因。

  • Value:返回被绑定到 Context 的值,是一个键值对,所以要通过一个Key才可以获取对应的值,这个值一般是线程安全的。

2. 为什么要用Context

  • 用于控制goroutine的结束,但它解决的并不是 能不能 的问题,而是解决 更好用 的问题。

2.1. 当不用Context时,利用channel+select来主动让goroutine停止

示例1


package mainimport ("fmt""time"
)/*
1. 利用channel控制goroutine的停止
*/func main() {stopChan := make(chan bool)go func() {for {select {case <-stopChan:fmt.Println("goroutin1 exit.")returndefault:fmt.Println("goroutin1 sleep 1s, keep going.")time.Sleep(time.Second * 2)}}}()go func() {for {select {case <-stopChan:fmt.Println("goroutin2 exit.")returndefault:fmt.Println("goroutin2 sleep 1s, keep going.")time.Sleep(time.Second * 3)}}}()time.Sleep(10 * time.Second)fmt.Println("10s 时间到了,主进程需要退出了.")// 发送信号让goroute1结束stopChan <- true// 发送信号让goroute2结束stopChan <- truetime.Sleep(5 * time.Second)
}

示例2

package mainimport ("fmt""time"
)/*1. 利用关闭channel的方法,让2个goroutine同时结束
*/func main() {stopChan := make(chan bool)go func() {for {select {case <-stopChan:fmt.Println("goroutin1 exit.")returndefault:fmt.Println("goroutin1 sleep 1s, keep going.")time.Sleep(time.Second * 2)}}}()go func() {for {select {case <-stopChan:fmt.Println("goroutin2 exit.")returndefault:fmt.Println("goroutin2 sleep 1s, keep going.")time.Sleep(time.Second * 3)}}}()time.Sleep(10 * time.Second)fmt.Println("10s 时间到了,主进程需要退出了.")// 利用关闭channel的方法,让2个goroutine同时结束close(stopChan)time.Sleep(5 * time.Second)
}

2.2 使用context来主动让goroutine停止

先ctx, cancel := context.WithCancel(context.Background()) 创建一个ctx实例
再利用cancel()函数执行控制goroutine的停止

package mainimport ("context""fmt""time"
)/*
// 利用context,手动让2个goroutine同时结束[是不是更简单?]
*/
func main() {ctx, cancel := context.WithCancel(context.Background())go func() {for {select {case <-ctx.Done():fmt.Println("goroutin1 exit.")returndefault:fmt.Println("goroutin1 sleep 1s, keep going.")time.Sleep(time.Second * 1)}}}()go func() {for {select {case <-ctx.Done():fmt.Println("goroutin2 exit.")returndefault:fmt.Println("goroutin2 sleep 1s, keep going.")time.Sleep(time.Second * 1)}}}()time.Sleep(10 * time.Second)fmt.Println("10s 时间到了,goroutine需要退出了.")// 利用context的方法,手动让2个goroutine同时结束cancel()time.Sleep(5 * time.Second)
}

2.3 使用context实现goroutine的超时控制

  • 使用场景:让goroutine执行一个任务,如果在指定时间内没有完成,这利用context的WithTimeout()主动让goroutine退出
package mainimport ("fmt""time""context"
)// 场景: 如果你需要对一个用协程启动的函数做超时控制,可以用context来完成goroutine的控制func main()  {// 设置一个用于超时控制的context ctx, ctx作为参数可以用来作为协程的超时控制ctx,cancel := context.WithTimeout(context.Background(),10 * time.Second)defer cancel()// ctx作为参数传递给需要做超时控制的函数go Monitor(ctx)time.Sleep(20 * time.Second)
}func Monitor(ctx context.Context)  {for {select {// 如果context 超时,ctx.Done()就会返回一个空接口 struct{}case <- ctx.Done():// 如果超时时间到了,就退出循环fmt.Println(ctx.Err())return// 如果没有超时,打印输出后继续循环default:time.Sleep(1*time.Second)fmt.Println("monitor")}}
}

2.4 利用context向goroutine传递参数

  • 除了超时控制与主动停止goroutine,还有可以通过Context传递上下文变量给其他协程。这样可以避免在协程之间传递大量的变量,代码更整洁可维护。下面的例子通过WithValue传递给协程一个变量,并且通过channel在协程之间通信。
package mainimport ("context""fmt""time"
)func main() {// 为ctx设置一个key-valuectx := context.Background()ctx = context.WithValue(ctx, "hello", "world")x := ctx.Value("hello")fmt.Println("x=", x) // world// 将key-vluae值传递到goroutinego work(ctx)time.Sleep(3 * time.Second)}
func work(ctx context.Context) {fmt.Println("do worker.")fmt.Println("hello=", ctx.Value("hello")) // world,利用context传递key-value// 继续传递到下层goroutinego subwork(ctx)
}func subwork(ctx context.Context) {fmt.Println("do subwork.")fmt.Println("hello=", ctx.Value("hello")) // world,利用context传递key-value到更进一层
}

程序输出:

x= world
do worker.
world
do subwork.
world

相关文章:

go语言-context的基本使用

1. 什么是 Context&#xff1f; Go 1.7 标准库引入 context&#xff0c;中文译作“上下文”&#xff0c;准确说它是 goroutine 的上下文&#xff0c;包含 goroutine 的运行状态、环境、现场等信息。 context 主要用来在 goroutine 之间传递上下文信息&#xff0c;包括&#x…...

《计算机网络简易速速上手小册》第9章:物联网(IoT)与网络技术(2024 最新版)

文章目录 9.1 IoT 架构与通信协议 - 打造智能世界的秘诀9.1.1 基础知识9.1.2 重点案例&#xff1a;使用 Python 和 MQTT 实现智能家居照明系统准备工作Python 脚本示例发布者&#xff08;灯光控制&#xff09;订阅者&#xff08;灯光状态接收&#xff09;&#xff1a; 9.1.3 拓…...

开源博客项目Blog .NET Core源码学习(8:EasyCaching使用浅析)

开源博客项目Blog使用EasyCaching模块实现缓存功能&#xff0c;主要是在App.Framwork项目中引用了多类包&#xff0c;包括内存缓存&#xff08;EasyCaching.InMemory&#xff09;、Redis缓存&#xff08;EasyCaching.CSRedis&#xff09;&#xff0c;同时支持多种序列化方式&am…...

windows下docker的使用

目录 1&#xff1a;docker是什么&#xff0c;能干什么&#xff1f; 2&#xff1a;docker下初始化一个容器 1&#xff1a;工具支持 2&#xff1a;运行装载docker镜像 a&#xff1a;在docker toolbox底下有个start.sh&#xff0c;我们进去里面修改里面路径配置&#xff1a; …...

C语言——R/预处理详解

一、预定义符号 C语⾔设置了⼀些预定义符号&#xff0c;可以直接使⽤&#xff0c;预定义符号也是在预处理期间处理的。 __FILE__ //进⾏编译的源⽂件 __LINE__ //⽂件当前的⾏号 __DATE__ //⽂件被编译的⽇期 __TIME__ //⽂件被编译的时间 __STDC__ //如果编译器遵循ANSI C&a…...

Unity_PackageManager缺失

Unity_PackageManager缺失 Unity早期版本不带PakageManager&#xff0c;或是人为因素造成PakageManager缺失。 关闭Unity工程&#xff0c;在项目文件下Packages文件夹里打开manifest.json&#xff0c;修改添加一行&#xff1a; "com.unity.package-manager-ui": &q…...

Megatron-LM源码系列(七):Distributed-Optimizer分布式优化器实现Part2

1. 使用入口 DistributedOptimizer类定义在megatron/optimizer/distrib_optimizer.py文件中。创建的入口是在megatron/optimizer/__init__.py文件中的get_megatron_optimizer函数中。根据传入的args.use_distributed_optimizer参数来判断是用DistributedOptimizer还是Float16O…...

[SWPUCTF 2021 新生赛]ez_unserialize

根据下面的user_agent和Disallow可以判断这个是在robots.txt 我们看的出来这是一个反序列化需要我们adminadmin passwdctf construct 构造方法&#xff0c;当一个对象被创建时调用此方法&#xff0c;不过unserialize()时却不会被调用 destruct 析构方法&#xff0c;PHP将在对象…...

android tv开发-1,leanback 2

目录 presenter太多,如何理清关系 动画与点击 tv的登录与设置 搜索功能 带二级菜单的页面 presenter太多,如何理清关系 leanback里面已经定义好了adapter与presenter,直接继承它就可以了 private DefaultObjectAdapter mVideoAdapter; private VideoCardPresenter mCardP…...

Spring Boot注解

Spring Boot提供了许多常用的注解&#xff0c;用于简化开发过程和配置管理。以下是一些常用的Spring Boot注解&#xff1a; SpringBootApplication: 标记一个类为Spring Boot应用程序的入口点&#xff0c;同时也是一个组合注解&#xff0c;包括了Configuration、EnableAutoConf…...

JavaWeb中的Filter(过滤器)和 Listener(监听器)

提示&#xff1a;这两个东西听起来似乎很难&#xff0c;实际上是非常简单的&#xff0c;按照要求写就行了&#xff0c;一定不要被新名词给吓到了。 JavaWeb中的Filter&#xff08;过滤器&#xff09; 一、Filter&#xff08;过滤器&#xff09;1.如何编写 Filter2.Filter 中的细…...

mybatis查询修改mysql的json字段

前言&#xff1a; mysql5.7版本之后支持json字段类型&#xff0c;推荐mysql8版本&#xff0c;适用于属性不确定的个性化字段&#xff0c;比如: 身份信息{“职业”,“学生”,“兴趣”:“打乒乓球”,“特长”:“跳高&#xff0c;书法”}; 图片信息{“日期”:“2023-12-12 22:12”…...

实时聊天系统

这个系统可以用于网站的即时通讯&#xff0c;比如客服系统、在线社区等。这个功能不仅对用户友好&#xff0c;而且也是检验技术实现能力的一个很好的案例。 ### 功能概述 该系统允许用户在网站上实时发送和接收消息。为了保持实时性&#xff0c;我们将使用PHP进行服务器端的逻…...

Spring-mvc、Spring-boot中如何在调用同类方法时触发AOP

1. 问题描述 Spring-mvc和Spring-boot中aop可以实现代理的功能&#xff0c;我们可以借此实现事务和日志记录或者限流等多种操作。但是&#xff0c;如果你在一个方法中调用其同类下的其他方法的时候不会触发AOP。本文主要说明其原因及解决办法和实现原理。 2. 原因 AIOP的本质是…...

幻兽帕鲁服务器自动重启备份-python

幻兽帕鲁服务器自动重启备份-python 1. 前置知识点2. 目录结构3. 代码内容4. 原理解释5. 额外备注 基于python编写的服务器全自动管理工具&#xff0c;能够实现自动定时备份存档&#xff0c;以及在检测到服务器崩溃之后自动重新启动&#xff0c;并且整合了对于frp端口转发工具的…...

C# Onnx yolov8 水表读数检测

目录 效果 模型信息 项目 代码 训练数据 下载 C# Onnx yolov8 水表读数检测 效果 模型信息 Model Properties ------------------------- date&#xff1a;2024-01-31T10:18:10.141465 author&#xff1a;Ultralytics task&#xff1a;detect license&#xff1a;AGPL-…...

负载均衡下webshell连接

目录 一、什么是负载均衡 分类 负载均衡算法 分类介绍 分类 均衡技术 主要应用 安装docker-compose 2.1上传的文件丢失 2.2 命令执行时的漂移 2.3 大工具投放失败 2.4 内网穿透工具失效 3.一些解决方案 总结 一、什么是负载均衡 负载均衡&#xff08;Load Balanc…...

Spring面试大全-基础知识01

1.什么是Spring Spring框架是用于构建企业级Java的开源框架&#xff0c;他通过依赖注入和IOC容器帮我我们管理对象&#xff1b;支持AOP&#xff0c;将非业务功能&#xff08;日志&#xff0c;事务等&#xff09;从我们业务代码中分离出来&#xff0c;提高了代码的可维护性&…...

Transformer实战-系列教程4:Vision Transformer 源码解读2

&#x1f6a9;&#x1f6a9;&#x1f6a9;Transformer实战-系列教程总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 4、Embbeding类 self.embeddings Embeddings(config, img_sizeimg_size) class Embeddings(nn.…...

cesium-水平测距

cesium测量两点间的距离 <template><div id"cesiumContainer" style"height: 100vh;"></div><div id"toolbar" style"position: fixed;top:20px;left:220px;"><el-breadcrumb><el-breadcrumb-item&…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...