Golang中的上下文-context包的简介及使用

文章目录

    • 简介
    • context.Background()
    • 上下文取消函数
    • 上下文值传递
    • 建议
    • Reference

简介

Go语言中的context包定义了一个名为Context的类型,它定义并传递截止日期、取消信号和其他请求范围的值,形成一个链式模型。如果我们查看官方文档,它是这样说的:

context包定义了Context类型,它在API边界和进程之间传递截止日期、取消信号和其他请求范围的值。

包中的主要实体是Context本身,它是一个接口。它只有四个方法:

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

这里,

  • Deadline:返回应该取消上下文的时间,以及一个布尔值,当没有截止日期时为false
  • Done:返回一个只接收的空结构体通道,它发出上下文应该被取消的信号
  • Err:在完成通道打开时返回nil;否则它返回上下文取消的原因
  • Value:返回与当前上下文的某个键关联的值,如果没有该键的值,则返回nil

与标准库的其他接口相比,Context有许多方法,这些接口通常只有一两个方法。其中三个密切相关:

  • Deadline是取消的时间
  • Done信号上下文完成时
  • Err返回取消的原因

最后一个方法,Value,返回与某个键关联的值。包的其余部分是一系列函数,允许你创建不同类型的上下文。

为什么使用Context

  • 它简化了跨进程或API的截止日期和取消的实现。
  • 它为你的代码扩展做好准备,例如,使用Context会使你的代码清晰易操纵,通过将所有进程以子父关系链式连接,你可以将任何进程绑定/连接在一起。
  • 它易于使用。
  • 它是Goroutine安全的,即你可以在不同的Goroutine上运行相同的上下文而不会泄露。

context.Background()

Background是一个空的上下文,它不会被取消,没有截止日期,也不持有任何值。它主要由主函数用作根上下文或用于测试目的:

package mainimport ("context""fmt"
)func main() {ctx := context.Background()fmt.Println(ctx)
}

输出:

$ go run main.go
context.Background

输出是“context.Background”,它告诉我们这是一个空的Context,它是一个接口,在这个Context接口上,

所有这些数据目前都是nil或空的,因为我们有一个空的Context,即背景上下文,它永远不会被取消,没有截止日期,也没有值。Background通常用于main、init和测试中,以及作为传入请求的顶级上下文。

让我们对所有这些进行fmt.Println检查:

package mainimport ("context""fmt"
)func main() {ctx := context.Background()fmt.Println("ctx.Err() : ", ctx.Err())fmt.Println("ctx.Done() : ", ctx.Done())fmt.Println("ctx.Value(\"key\") : ", ctx.Value("key"))fmt.Print("ctx.Deadline() : ")fmt.Print(ctx.Deadline())
}

输出:

$ go run main.go
ctx.Err() :  <nil>
ctx.Done() :  <nil>
ctx.Value("key") :  <nil>
ctx.Deadline() : 0001-01-01 00:00:00 +0000 UTC false

上下文取消函数

Go语言的Context包被用来处理我们的进程或API中的请求流,通过将子上下文与父上下文链接起来,我们可以使用context.WithDeadlinecontext.WithTimeout方法在链中控制截止日期和取消信号。

Context的底层是无法改变的,他在main函数创建,之后传递给其他子函数,比如goroutine,子函数无法改变context,也无法被子进程取消

实例

与done channel不同的是,done是以关闭让其他关闭,而context中的cancel函数则是被调用的

父函数可以取消子函数

如果子函数创建了自己的子函数,也可以把这个context传递下去

那如果子函数想取消自己的子函数呢?

我们可以创建新的context,基于旧的context

我们来举个例子:

func main() {
// 初始化contextvar wg sync.WaitGroupctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)defer cancel()// 添加数据generator := func(data string, stream chan any) {for {select {case <-ctx.Done():returncase stream <- data:}}}infiniteApples := make(chan any)go generator("apple", infiniteApples)infiniteBananas := make(chan any)go generator("banana", infiniteBananas)infiniteOranges := make(chan any)go generator("orange", infiniteOranges)wg.Add(1)go func1(ctx, &wg, infiniteApples)func2 := genericFuncfunc3 := genericFuncwg.Add(1)go func2(ctx, &wg, infiniteBananas)wg.Add(1)go func3(ctx, &wg, infiniteOranges)wg.Wait()
}func func1(ctx context.Context, s *sync.WaitGroup, streams <-chan any) {defer s.Done()var wg sync.WaitGroupdoWOrks := func(CTX context.Context) {defer wg.Done()for {select {case <-CTX.Done():returncase d, ok := <-streams:if !ok {fmt.Println("stream closed")return}fmt.Println(d)}}}// 基于父上下文设置自己的上下文newCtx, cancel := context.WithTimeout(ctx, 3*time.Second)defer cancel()// 启动自己的子函数for i := 0; i < 3; i++ {wg.Add(1)go doWOrks(newCtx)}wg.Wait()
}// 沿用父函数的context
func genericFunc(ctx context.Context, s *sync.WaitGroup, apples chan any) {defer s.Done()for {select {case <-ctx.Done():returncase d, ok := <-apples:if !ok {fmt.Println("stream closed")return}fmt.Println(d)}}
}

在输出过程中,我们会发现apple先停止输出,最后5秒到了,另外两个goroutine也停止运行 。

上下文值传递

在Go语言中,context上下文可以通过WithValue函数来传递值。这个函数接受一个父上下文(parent Context)、一个键(key)和一个值(value),返回一个新的上下文(Context),这个新上下文与父上下文相同,但是增加了一个键值对。这个键值对可以在上下文的整个传递链中被检索。

以下是一个使用WithValue传递值的例子:

package mainimport ("context""fmt"
)func main() {// 创建一个带有值的上下文ctx := context.WithValue(context.Background(), "language", "Go")// 传递ctx到函数中process(ctx)
}func process(ctx context.Context) {// 从ctx中检索值if language, ok := ctx.Value("language").(string); ok {fmt.Println("Language:", language)}
}

在这个例子中,我们创建了一个带有键"language"和值"Go"的上下文。然后,我们将这个上下文传递给了process函数,在这个函数中,我们检索并打印出了这个值。

需要注意的是,context的值应该是请求范围的数据,而不是全局的。它通常用于传递请求相关的元数据,如请求ID、用户身份信息等。此外,由于context是并发安全的,所以它可以在多个goroutine之间安全地传递和使用。

建议

  • 每当你需要使用context.Context时,确保它总是作为第一个参数。
  • 始终使用“ctx”作为变量名,虽然使用其他变量名也可以正常工作,但遵循大多数人的做法是好的,像这样的事情你不需要与众不同。
  • 确保调用取消函数。
  • 不要在方法中使用结构体来添加上下文,始终将其作为参数添加,即context.Context
  • 不要过度使用context.WithValue

Reference

  1. Golang中context包使用场景和示例详解
  2. Golang Context Complete Tutorial with Examples
  3. The Go Blog: Go Concurrency Patterns: Context

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

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

相关文章

java.lang.NoClassDefFoundError: javax/validation/constraints/Min

1、报错截图 2、解决办法 添加依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId> </dependency>

基于SpringBoot Vue单位考勤管理系统

一、&#x1f4dd;功能介绍 基于SpringBoot Vue单位考勤管理系统 角色&#xff1a;管理员、员工 管理员&#xff1a;管理员进入系统主页面&#xff0c;主要功能包括对首页、个人中心、员工管理、部门信息管理、职位信息管理、加班申请管理、打卡信息管理、工作汇报管理、请假…

SpringBoot属性配置的多种方式

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉🍎个人主页:Leo的博客💞当前专栏: 循序渐进学SpringBoot ✨特色专栏: MySQL学习 🥭本文内容:SpringBoot属性配置的多种方式 📚个人知识库: Leo知识库,欢迎大家访问 目录 …

论文阅读——MVDiffusion

MVDiffusion: Enabling Holistic Multi-view Image Generation with Correspondence-Aware Diffusion 文生图模型 用于根据给定像素到像素对应关系的文本提示生成一致的多视图图像。 MVDiffusion 会在给定任意每个视图文本的情况下合成高分辨率真实感全景图像&#xff0c;或将…

备战蓝桥杯---数论相关问题

目录 一、最大公约数和最小公倍数 二、素数判断 三、同余 四、唯一分解定理 五、约数个数定理 六、约数和定理 五、快速幂 六、费马小定理 七、逆元 一、最大公约数和最小公倍数 文章链接&#xff1a;最大公约数和最小公倍数 二、素数判断 文章链接&#xff1a;在J…

C语言——#define的使用

#define定义常量 基本语法 #define name stuff //&#xff08;#define&#xff09;&#xff08;变量名&#xff09;&#xff08;定义的数值&#xff09; 这里记得&#xff0c;是不加分号的 定义常量&#xff08;这里 就要涉及我们经常说的宏定义&#xff09; 定义常量的使…

Python爬虫-爬取药膳食谱数据

&#x1f388; 博主&#xff1a;一只程序猿子 &#x1f388; 博客主页&#xff1a;一只程序猿子 博客主页 &#x1f388; 个人介绍&#xff1a;爱好(bushi)编程&#xff01; &#x1f388; 创作不易&#xff1a;喜欢的话麻烦您点个&#x1f44d;和⭐&#xff01; &#x1f388;…

前端学习之DOM编程案例:抽奖案例

代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>抽奖案例</title><style>*{margin: 0;padding: 0;}</style> </head> <body><div id"container"&g…

浅谈Redis和一些指令

浅浅谈一谈Redis的客户端 Redis客户端 Redis也是一个客户端/服务端结构的程序。 MySQL也是一个客户端/服务端结构的程序。 Redis的客户端也有多种形态 1.自带命令行客户端 redis-cli 2.图形化界面的客户端&#xff08;桌面程序&#xff0c;web程序&#xff09; 像这样的图形…

阿里云服务器可以干嘛?能干啥你还不知道么!

阿里云服务器可以干嘛&#xff1f;能干啥你还不知道么&#xff01;简单来讲可用来搭建网站、个人博客、企业官网、论坛、电子商务、AI、LLM大语言模型、测试环境等&#xff0c;阿里云百科aliyunbaike.com整理阿里云服务器的用途&#xff1a; 阿里云服务器活动 aliyunbaike.com…

Flutter学习12 - SharedPreferences

1、shared_preferences 插件 类似于 Android 中的 SharedPreferences&#xff0c;键值对的形式进行本地存储 1.1、引入插件 在 pubspec.yaml 中引入 dependencies:shared_preferences: ^2.1.0在需要用到的文件中引入 import package:shared_preferences/shared_preference…

二维相位解包理论算法和软件【全文翻译- 掩码(3.4)】

本节我们将研究从质量图中提取掩码的问题。掩码是一个质量图,其像素只有两个值:0 或 1。零值像素标志着质量最低的相位值,这些相位值将被屏蔽、零权重或忽略。第 5 章中的某些 L/ 正则算法需要使用掩码来定义零权重。掩码还可用于某些路径跟踪算法,如第 4.5 节中将要介绍的…

基于Springboot的美发管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的美发管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…

秋招刷题4(动态规划)

1.购物单 import java.util.Scanner;public class Main {public static void main(String[] args){Scanner sc new Scanner(System.in);int N sc.nextInt();int m sc.nextInt();Goods[] goods new Goods[m];for(int i 0; i < m; i){goods[i] new Goods();}for(int i …

9_springboot_shiro_jwt_多端认证鉴权_整合jwt

1. Shiro框架回顾 到目前为之&#xff0c;Shiro框架本身的知识点已经介绍完了。web环境下&#xff0c;整个框架从使用的角度我们需要关注的几个点&#xff1a; 要使用Shiro框架&#xff0c;就要创建核心部件securityManager 对象。 SpringBoot项目中&#xff0c;引入shiro-spr…

python小练习(ps:可评论区讨论)

1. (单选题)海龟初始坐标为&#xff08;0&#xff0c;0&#xff09;&#xff0c;让海龟往坐标原点后方移动200像素的语句是 A. turtle.penup(200)B. turtle.fd(200)C. turtle.goto(200)D. turtle.bk(200) 2. (单选题)改变海龟画笔尺寸的是 A. turtle.penwidth()B. turtle.pen…

分类预测 | Matlab实现DRN深度残差网络数据分类预测

分类预测 | Matlab实现DRN深度残差网络数据分类预测 目录 分类预测 | Matlab实现DRN深度残差网络数据分类预测分类效果基本介绍程序设计参考资料 分类效果 基本介绍 1.Matlab实现DRN深度残差网络数据分类预测&#xff08;完整源码和数据&#xff09;&#xff0c;运行环境为Matl…

智能数据采集API技术在电子商务跨境电商数字化转型中的核心作用|API数据采集接口的核心应用

随着科技的飞速发展和全球化的深入推进&#xff0c;数字化转型已经成为企业和社会发展的必然趋势。在这一背景下&#xff0c;智能数据采集技术作为数字化转型的核心驱动力&#xff0c;正发挥着越来越重要的作用。本文将从智能数据采集技术的定义、特点、应用场景以及对企业的影…

MES实施之工控机和电脑的选择

在MES项目实施过程中,经常会碰到工控机和电脑的选型问题,那么他们的区别是什么? 1、控机和普通个人电脑(PC)相比,具有以下几个区别: 1.运行环境不同:工控机通常需要在各种恶劣的工业环境中运行,如高温、高湿、强电磁干扰等,因此需要具有防尘、防水、抗干扰等特点。而…

基于Spring Boot的简历系统设计与开发

基于Spring Boot的简历系统设计与开发 开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/idea 部分系统展示 前台首页界面 简历模板管理界面 用户管理界面 管理员登录界…