Go | context

Go | context

ChatGPT辅助编写

1. 简介

Go语言的context包是用于在并发编程中传递请求作用域的工具。它解决了在多个goroutine之间传递请求相关数据、控制请求超时、取消请求等问题。

2. 核心接口

Go语言中context包的核心接口是context.Context。它定义了用于传递请求作用域的方法和属性。Context接口包含以下几个主要方法:

  1. Deadline() (deadline time.Time, ok bool):返回上下文的截止时间(deadline)。如果上下文没有设置截止时间,ok会返回false。

  2. Done() <-chan struct{}:返回一个通道,当上下文被取消或超时时,该通道会被关闭。

  3. Err() error:返回上下文被取消的原因。如果上下文没有被取消,则返回nil。

  4. Value(key interface{}) interface{}:获取与指定键相关联的值。这对于在请求范围内传递数据很有用。

除了这些方法之外,Context接口还包含了一些私有方法,这些方法主要是用于包内实现,而不是供外部使用。

通过这些方法,我们可以控制请求的超时、取消请求,以及在并发编程中传递请求相关的值,使得程序的并发处理更加可靠和灵活。

3. 核心方法

3.1. context.WithCancel

context.WithCancel函数用于创建一个可取消的context,可以通过调用返回的cancel函数来取消该context。下面是一个Go语言代码演示如何使用context.WithCancel

package mainimport ("context""fmt""time"
)func longRunningTask(ctx context.Context) {for {select {case <-time.After(1 * time.Second):fmt.Println("任务正在执行...")case <-ctx.Done():fmt.Println("任务被取消")return}}
}func main() {// 创建一个父contextparentCtx := context.Background()// 创建一个可取消的子context,并得到一个用于取消的函数ctx, cancel := context.WithCancel(parentCtx)// 启动长时间运行的任务,传入子contextgo longRunningTask(ctx)// 等待3秒后取消任务time.Sleep(3 * time.Second)cancel()// 等待一段时间,以确保长时间运行的任务完成time.Sleep(2 * time.Second)
}

在上面的代码中,我们首先创建了一个父context,使用context.Background()函数。然后,我们使用context.WithCancel函数创建了一个可取消的子context,并得到了一个cancel函数。该函数可以用于取消子context。在longRunningTask函数中,我们使用select语句来等待任务执行或者收到子context的取消信号。

主goroutine等待3秒后,我们调用cancel函数来取消子context,从而触发长时间运行的任务接收到取消信号而退出。然后,我们等待一段时间,以确保长时间运行的任务完成。

运行这个代码,您会看到类似以下内容的输出:

任务正在执行...
任务正在执行...
任务正在执行...
任务被取消

3.2. context.WithTimeout

context.WithTimeout函数用于创建一个带有超时的context,超过指定的时间后,context会自动被取消。下面是一个Go语言代码演示如何使用context.WithTimeout

package mainimport ("context""fmt""time"
)func longRunningTask(ctx context.Context) {for {select {case <-time.After(1 * time.Second):fmt.Println("任务正在执行...")case <-ctx.Done():fmt.Println("任务被取消或超时")return}}
}func main() {// 创建一个带有5秒超时的contextctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)defer cancel()// 启动长时间运行的任务,传入带超时的contextgo longRunningTask(ctx)// 等待一段时间,以确保长时间运行的任务完成time.Sleep(8 * time.Second)
}

在上面的代码中,我们使用context.WithTimeout函数创建了一个带有5秒超时的context,并得到了一个cancel函数。然后,我们启动了一个长时间运行的任务,传入了这个带超时的context。

主goroutine等待8秒后,超过了context的超时时间。在超过5秒后,带超时的context会自动取消,长时间运行的任务接收到了取消信号而退出。

运行这个代码,您会看到类似以下内容的输出:

任务正在执行...
任务正在执行...
任务正在执行...
任务正在执行...
任务正在执行...
任务被取消或超时

这证明了在5秒后,带超时的context成功地取消了长时间运行的任务,因为任务超过了指定的超时时间。

3.3. context.WithDeadline

context.WithDeadline函数用于创建一个带有截止时间的context,超过指定的时间后,context会自动被取消。下面是一个Go语言代码演示如何使用context.WithDeadline

package mainimport ("context""fmt""time"
)func longRunningTask(ctx context.Context) {for {select {case <-time.After(1 * time.Second):fmt.Println("任务正在执行...")case <-ctx.Done():fmt.Println("任务被取消或超时")return}}
}func main() {// 设置截止时间为5秒后deadline := time.Now().Add(5 * time.Second)// 创建一个带有截止时间的contextctx, cancel := context.WithDeadline(context.Background(), deadline)defer cancel()// 启动长时间运行的任务,传入带截止时间的contextgo longRunningTask(ctx)// 等待一段时间,以确保长时间运行的任务完成time.Sleep(8 * time.Second)
}

在上面的代码中,我们使用time.Now().Add(5 * time.Second)来设置截止时间为当前时间加上5秒。然后,我们使用context.WithDeadline函数创建了一个带有截止时间的context,并得到了一个cancel函数。接着,我们启动了一个长时间运行的任务,传入了这个带截止时间的context。

主goroutine等待8秒后,超过了context的截止时间。在超过5秒后,带截止时间的context会自动取消,长时间运行的任务接收到了取消信号而退出。

运行这个代码,您会看到类似以下内容的输出:

任务正在执行...
任务正在执行...
任务正在执行...
任务正在执行...
任务正在执行...
任务被取消或超时

这证明了在截止时间到达后,带截止时间的context成功地取消了长时间运行的任务。

3.4. WithValue

context.WithValue函数用于创建一个带有键值对的context,这些键值对可以在整个context范围内传递。下面是一个Go语言代码演示如何使用context.WithValue

package mainimport ("context""fmt""time"
)type keyType stringfunc longRunningTask(ctx context.Context) {if value, ok := ctx.Value(keyType("name")).(string); ok {fmt.Printf("任务正在执行,欢迎 %s\n", value)} else {fmt.Println("任务正在执行...")}
}func main() {// 创建一个带有键值对的contextctx := context.WithValue(context.Background(), keyType("name"), "John")// 启动长时间运行的任务,传入带键值对的contextgo longRunningTask(ctx)// 等待一段时间,以确保长时间运行的任务完成time.Sleep(time.Second)
}

在上面的代码中,我们使用context.WithValue函数创建了一个带有键值对的context,并将"John"作为值与"keyType"作为键关联起来。接着,我们启动了一个长时间运行的任务,并在任务中根据键来获取传递的值,然后根据值进行相应的输出。

在主goroutine中,我们使用time.Sleep(time.Second)来保持程序运行,以便长时间运行的任务有足够的时间来执行。

运行这个代码,您会看到类似以下内容的输出:

任务正在执行,欢迎 John

这证明了我们成功地在长时间运行的任务中传递了键值对,并根据传递的值做了相应的处理。这种方式可以在整个context范围内传递请求相关的值,非常适合需要在并发处理中共享信息的场景。

3.5. 组合使用

在Go语言中,您可以组合使用context.WithCancelcontext.WithTimeoutcontext.WithDeadlinecontext.WithValue来实现更复杂的场景。下面是一个示例代码演示了这种组合用法:

package mainimport ("context""fmt""time"
)type keyType stringfunc longRunningTask(ctx context.Context) {for {select {case <-time.After(1 * time.Second):if value, ok := ctx.Value(keyType("name")).(string); ok {fmt.Printf("任务正在执行,欢迎 %s\n", value)} else {fmt.Println("任务正在执行...")}case <-ctx.Done():fmt.Println("任务被取消或超时")return}}
}func main() {// 创建一个带有截止时间的context,截止时间为当前时间加上5秒deadline := time.Now().Add(5 * time.Second)ctx, cancel := context.WithDeadline(context.Background(), deadline)defer cancel()// 在带截止时间的context中添加一个键值对ctxWithValue := context.WithValue(ctx, keyType("name"), "John")// 启动长时间运行的任务,传入带截止时间和键值对的contextgo longRunningTask(ctxWithValue)// 等待一段时间,以确保长时间运行的任务完成time.Sleep(8 * time.Second)
}

在上面的代码中,我们首先使用context.WithDeadline函数创建了一个带有截止时间的context,并得到了一个cancel函数。然后,我们使用context.WithValue函数在该context中添加了一个键值对。

接着,我们启动了一个长时间运行的任务,并传入了带有截止时间和键值对的context。在任务中,我们在每秒钟输出欢迎信息,如果在context中存在"name"键值对,那么输出欢迎该名字的信息。

主goroutine等待8秒后,超过了context的截止时间。在超过5秒后,带截止时间的context会自动取消,长时间运行的任务接收到了取消信号而退出。

运行这个代码,您会看到类似以下内容的输出:

任务正在执行,欢迎 John
任务正在执行,欢迎 John
任务正在执行,欢迎 John
任务正在执行,欢迎 John
任务正在执行,欢迎 John
任务被取消或超时

这证明了在截止时间到达后,带截止时间的context成功地取消了长时间运行的任务,并且任务在上下文中获取到了传递的键值对。这种组合使用的方式非常灵活,可以根据需求进行不同的扩展和组合。

4. 核心思想

在Go语言中,context的上下层关系可以通过context.WithXXX函数来构建。每个WithXXX函数都会返回一个新的context,该context会继承前一个context的属性,并在此基础上添加新的功能。下面是一个演示context上下层关系的示例代码:

package mainimport ("context""fmt""time"
)func longRunningTask(ctx context.Context, name string) {for {select {case <-time.After(1 * time.Second):fmt.Printf("%s 正在执行任务...\n", name)case <-ctx.Done():fmt.Printf("%s 任务被取消或超时\n", name)return}}
}func main() {// 创建一个父context,设置超时时间为5秒parentCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)defer cancel()// 在父context的基础上,创建一个子context,继承父context的超时时间childCtx, _ := context.WithCancel(parentCtx)// 启动两个长时间运行的任务,分别使用子context和父contextgo longRunningTask(childCtx, "任务1")go longRunningTask(parentCtx, "任务2")// 主goroutine等待3秒后取消子context,模拟任务1超时time.Sleep(3 * time.Second)cancel()// 等待一段时间,以确保长时间运行的任务2完成time.Sleep(2 * time.Second)
}

在上面的代码中,我们首先使用context.WithTimeout函数创建了一个父context,并设置了超时时间为5秒。然后,我们使用context.WithCancel函数在父context的基础上创建了一个子context,并继承了父context的超时时间。

接着,我们启动了两个长时间运行的任务,分别使用子context和父context。其中,任务1使用子context,任务2使用父context。在任务1中,我们在每秒钟输出任务正在执行的信息。在任务2中,我们同样在每秒钟输出信息。

主goroutine等待3秒后,我们调用了cancel函数,取消了子context,模拟了任务1的超时情况。而任务2仍然会继续执行。

运行这个代码,您会看到类似以下内容的输出:

任务1 正在执行任务...
任务2 正在执行任务...
任务1 任务被取消或超时
任务2 正在执行任务...
任务2 正在执行任务...
任务2 正在执行任务...
任务2 任务被取消或超时

这证明了在父context的基础上创建了子context,并且子context继承了父context的超时时间。在子context中调用cancel函数会取消该context及其衍生的所有子context,从而导致长时间运行的任务接收到取消信号而退出。而父context不受子context的影响,继续执行。

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

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

相关文章

【MySQL】根据多个字段查询数据进行去重的sql编写

Mysql根据查询语句-根据多个字段进行数据去重 一、实现思路 根据四个字段进行数据去重的SQL编写可以使用GROUP BY和HAVING子句来实现。 场景一&#xff1a; 假设有一个名为table1的数据表&#xff0c;其中包含四个字段&#xff1a;field1、field2、field3和field4。要求根据这…

Python+request+pytest 接口自动化测试框架入门(与unittest的比较)

1. Pythonrequestpytest 接口自动化测试框架入门 - 简书 pytest和unittest的比较&#xff1a; pytest是一个非常成熟的全功能的Python测试框架&#xff0c;主要有以下几个特点&#xff1a; 简单灵活&#xff0c;容易上手支持参数化能够支持简单的单元测试和复杂的功能测试&a…

进程与线程

概念 程序&#xff1a;程序是一组指令的集合&#xff0c;它描述了完成特定任务的步骤和操作。程序通常以源代码的形式编写&#xff0c;可以使用编程语言如C、Java、Python等来表示。程序本身是静态的&#xff0c;它只是存储在存储介质&#xff08;如硬盘&#xff09;上的一段代…

深入学习 Redis - 深挖经典数据类型之 zset

目录 前言 一、zset 类型 1.1、操作命令 zadd / zrange&#xff08;添加 / 查询&#xff09; zcard&#xff08;个数&#xff09; zcount&#xff08;区间元素个数&#xff09; zrevrange&#xff08;逆序展示&#xff09; zrangebyscore&#xff08;按分数找元素&#…

【UE5 多人联机教程】06-显示玩家名称

效果 可以看到玩家输入各自的名称&#xff0c;会显示到自己控制的角色头上。但是目前有一个BUG就是&#xff0c;当客户端加入游戏时会多创建一个服务端的角色。 步骤 1. 打开“BP_ThirdPersonCharacter”&#xff0c;添加一个控件组件&#xff0c;用于显示玩家名称 作为网格体…

内存函数讲解

&#x1f495;"痛苦难以避免&#xff0c;而磨难可以选择。"-->村上春树&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;数据在内存中的存储 内存函数就是管理内存数据的函数&#xff0c;包含于头文件<string.h>中 1.memcpy函数-->内存…

Caused by: org.springframework.beans.factory.

问题解决:Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name IUserRepository defined in app.test4.OpportunityMatching.IUserRepository defined in EnableJpaRepositories declared on JpaRepositoriesRegistrar.Enable…

STL常用容器-map

STL常用容器-map map/multimap容器1.1 map基本概念1.2 map构造和赋值1.3 map大小和交换1.4 map插入和删除1.5 map查找和统计1.6 map容器排序 map/multimap容器 1.1 map基本概念 简介&#xff1a; map中所有元素都是pairpair中第一个元素为key&#xff08;键值&#xff09;&a…

Docker 容器访问宿主机服务

docker 网络简介 docker 在安装时会默认创建三个网络&#xff1a;bridge&#xff08;默认网络模式&#xff09;、 none 、host。 host 直接和宿主机共用网络。bridge 网络隔离&#xff0c;通过虚拟网桥&#xff08;一般是 docker0&#xff09;与宿主机通信。none 禁用网络功能…

Jenkins插件管理切换国内源地址

一、替换国内插件下载地址 选择系统管理–>插件管理–> Available Plugins 并等待页面完全加载完成、这样做是为了把jenkins官方的插件列表下载到本地、接着修改地址文件、替换为国内插件地址 进入插件文件目录 cd /var/lib/jenkins/updatesdefault.json 为插件源地址…

tinymce实现将word中内容(文字图片等)直接粘贴至编辑器中——利用插件tinymce-powerpaste-plugin

TinyMCE是一款易用、且功能强大的所见即所得的富文本编辑器。同类程序有&#xff1a;UEditor、Kindeditor、Simditor、CKEditor、wangEditor、Suneditor、froala等等。 TinyMCE的优势&#xff1a; 开源可商用&#xff0c;基于LGPL2.1 插件丰富&#xff0c;自带插件基本涵盖日常…

技术笔记2023076 rBoot学习7

技术笔记2023076 rBoot学习7 继续之前的学习。 代码分析&#xff1a;函数find_image() // prevent this function being placed inline with main // to keep mains stack size as small as possible // dont mark as static or itll be optimised out when // using the ass…

给APK签名—两种方式(flutter android 安装包)

前提&#xff1a;给未签名的apk签名&#xff0c;可以先检查下apk有没有签名 通过命令行查看&#xff1a;打开终端或命令行界面&#xff0c;导入包含APK文件的目录&#xff0c;并执行以下命令&#xff1a; keytool -printcert -jarfile your_app.apk 将 your_app.apk替换为要检查…

String 的 switch-case 实现原理

前面我们已经知道 String 的 switch-case 实现原理 依据 case 值的稀疏程度&#xff0c;分别由两个指令 - tableswitch 和 lookupswitch 实现&#xff0c;但是这两个指令都支持整型&#xff0c; 如何让 String 类型的值 也支持 String 的 switch-case 实现原理 public class T…

【数据结构】--189.轮转数组

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

Rethinking the Image Fusion(PMGI)

1.摘要 本文提出了一种基于梯度和强度比例维护&#xff08;PMGI&#xff09;的快速统一图像融合网络&#xff0c;可以端到端实现各种图像融合任务&#xff0c;包括红外和可见图像融合、多曝光图像融合、医学图像融合、多焦点图像融合和全色增强。我们将图像融合问题统一为源图…

保姆级系列教程-玩转Fiddler抓包教程(1)-HTTP和HTTPS基础知识

1.简介 有的小伙伴或者童鞋们可能会好奇地问&#xff0c;不是讲解和分享抓包工具了怎么这里开始讲解HTTP和HTTPS协议了。这是因为你对HTTP协议越了解&#xff0c;你就能越掌握Fiddler的使用方法&#xff0c;反过来你越使用Fiddler&#xff0c;就越能帮助你了解HTTP协议。 Fid…

Java | 继承、多态、抽象类与接口

目录 一、类的继承 二、Object类 2.1 getClass()方法 2.2 toString()方法 2.3 equals()方法 三 、对象类型的转换 3.1 向上转换 3.2 向下转型 四、使用instanceof关键字判断对象类型 五、方法的重载 六、final关键字 6.1 final变量 6.2 final方法 6.3 final类 七…

安装x265

一、编译libx265源码 libx265是用CMAKE编译的&#xff0c;故先下cmake&#xff0c;我是centos系统&#xff0c;命令&#xff1a; yum install cmake -y进入目录./x265_1.9/build/linux/下&#xff0c;执行脚本&#xff1a; sh make-Makefiles.bash选择好之后&#xff0c;输入…

【多模态】19、RegionCLIP | 基于 Region 来实现视觉语言模型预训练

文章目录 一、背景二、方法2.1 Region-based Language-Image Pretraining2.2 目标检测的迁移学习 三、效果3.1 数据集3.2 实现细节3.3 结果 论文&#xff1a; RegionCLIP: Region-based Language-Image Pretraining 代码&#xff1a;https://github.com/microsoft/RegionCLIP …