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.rhkb.cn/news/304960.html

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

相关文章

Ollama利用嵌入模型实现RAG应用

Ollama支持embedding models嵌入模型&#xff0c;从而支持RAG&#xff08;retrieval augmented generation&#xff09;应用&#xff0c;结合文本提示词&#xff0c;检索到文档或相关数据。嵌入模型是通过训练生成向量嵌入&#xff0c;这是一长串数字数组&#xff0c;代表文本序…

练习 21 Web [GXYCTF2019]BabySQli

SQL联合查询&#xff0c;注意有源码看源码&#xff0c;Base64以及32的区别&#xff0c;MD5碰撞 打开后有登录框&#xff0c;先随意登录尝试 只有输入admin才是返回wrong pass&#xff01; 其他返回wrong user 所以用户名字段一定要输入admin 养成好习惯&#xff0c;先查看源码…

kali上python3切换python2环境

一、然后打开终端输入 python --version 二、 打开终端分别输入下面两条命令&#xff1a; update-alternatives --install /usr/bin/python python /usr/bin/python2 100 update-alternatives --install /usr/bin/python python /usr/bin/python3 150 三、 如果需要切换python版…

Windows系统C盘空间优化进阶:磁盘清理与Docker日志管理

Windows系统C盘空间优化进阶&#xff1a;磁盘清理与Docker日志管理 文章目录 Windows系统C盘空间优化进阶&#xff1a;磁盘清理与Docker日志管理磁盘清理工具 使用“运行”命令访问磁盘清理利用存储感知自动管理空间清理WinSxS文件夹结合手动清理策略 小结删除临时文件总结&…

流式密集视频字幕

流式密集视频字幕 摘要1 IntroductionRelated Work3 Streaming Dense Video Captioning Streaming Dense Video Captioning 摘要 对于一个密集视频字幕生成模型&#xff0c;预测在视频中时间上定位的字幕&#xff0c;理想情况下应该能够处理长的输入视频&#xff0c;预测丰富、…

Linux系统概述与安装

Linux的介绍 Linux内核 Linux内核是 Linux 操作系统主要组件&#xff0c;也是计算机硬件与其软件之间的交互入口。它负责两者之间的通信&#xff0c;还要尽可能高效地管理资源 Linux Shell shell是系统的用户界面&#xff0c;提供了用户与内核进行交互操作的一种接口 Linux文…

java数组.day16(冒泡排序,稀疏数组)

冒泡排序 冒泡排序无疑是最为出名的排序算法之一&#xff0c;总共有八大排序! 冒泡的代码还是相当简单的&#xff0c;两层循环&#xff0c;外层冒泡轮数&#xff0c;里层依次比较&#xff0c;江湖中人人尽皆知。 我们看到嵌套循环&#xff0c;应该立马就可以得出这个算法的时…

2024中国航空航天暨无人机展览会8月在重庆举办

2024中国航空航天暨无人机展览会8月在重庆举办 邀请函 主办单位&#xff1a; 中国航空学会 重庆市南岸区人民政府 招商执行单位&#xff1a; 重庆港华展览有限公司 展会背景&#xff1a; 为更好的培养航空航天产业人才&#xff0c;汇聚航空教育产业创新科技&#xff0c;…

CTK插件框架学习-事件监听(07)

CTK插件框架学习-服务工厂(06)https://mp.csdn.net/mp_blog/creation/editor/137295686 一、简介 事件监听指当事件发生变化时所产生的通信&#xff0c;是动态的&#xff0c;对于已经发生过的事件无法监听 二、事件类型 1、框架事件 监听框架状态变化&#xff0c;因为监听…

usb_camera传输视频流编码的问题记录!

前言&#xff1a; 大家好&#xff0c;今天给大家分享的内容是&#xff0c;一个vip课程付费的朋友&#xff0c;在学习过程中遇到了一个usb采集的视频数据流&#xff0c;经过ffmpeg编码&#xff0c;出现了问题&#xff1a; 问题分析&#xff1a; 其实这个问题不难&#xff0c;关键…

git安装配置教程(小白保姆教程2024最新版)

目录 一、Git是什么?二、安装Git1.下载git2.安装git3.检测git 三、配置Git1.配置本地信息2.配置SSH1&#xff09;SSH与SSH Key是什么&#xff1f;2&#xff09;生成SSH Key3&#xff09;获取ssh key公钥内容&#xff08;id_rsa.pub&#xff09;4&#xff09;Github账号上添加公…

这段程序有点神奇,你能读懂么?

下面的程序在一个打开的文档中查找特定的字符串&#xff0c;这个字符串是“可以”&#xff0c;查找并仅保留最后的3次&#xff0c;抛弃其他的内容&#xff0c;请试运行一下&#xff0c;看看结果是否正确&#xff1f; from collections import deque def search(lines, pattern,…

【SpringBoot】配置swagger

pom.xml 安装插件 <dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version></dependency>创建swagger配置类 import org.springframework.context.annotation.…

如何使用Tomcat+cpolar搭建本地站点并发布到公网分享好友远程访问

文章目录 前言1.本地Tomcat网页搭建1.1 Tomcat安装1.2 配置环境变量1.3 环境配置1.4 Tomcat运行测试1.5 Cpolar安装和注册 2.本地网页发布2.1.Cpolar云端设置2.2 Cpolar本地设置 3.公网访问测试4.结语 前言 Tomcat作为一个轻量级的服务器拥有强大功能&#xff0c;由于其可以实…

如何使用Java和RabbitMQ实现延迟队列?

前言 今天我们使用Java和RabbitMQ实现消息队列的延迟功能。 前期准备&#xff0c;需要安装好docker、docker-compose的运行环境。 需要安装RabbitMQ的可以看下面这篇文章。 如何使用PHP和RabbitMQ实现消息队列&#xff1f;-CSDN博客 今天讲的是依赖RabbitMQ的延迟插件实现…

头歌-机器学习 第10次实验 逻辑回归

第1关&#xff1a;逻辑回归核心思想 任务描述 本关任务&#xff1a;根据本节课所学知识完成本关所设置的编程题。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a; 什么是逻辑回归&#xff1b; sigmoid函数。 什么是逻辑回归 当一看到“回归”这两个字&a…

【opencv】示例-falsecolor.cpp 使用OpenCV函数动态地对图像应用不同的色彩映射

该代码是一个使用OpenCV库实现的C程序&#xff0c;主要用来展示如何通过applyColorMap函数将色彩映射应用到一个灰度图像上&#xff0c;并提供一个滑动条来实时改变色彩映射的效果。此外&#xff0c;该程序还可以绘制包含不同形状的灰度图像&#xff0c;用作applyColorMap函数的…

QT 线程之movetothread

上文列举了qt中线程的几种方法&#xff0c;其中2种方法最为常见。 这两种方法都少不了QThread类&#xff0c;前者继承于QThread类&#xff0c;后者复合QThread类。 本文以实例的方式描述了movetothread&#xff08;&#xff09;这种线程的方法&#xff0c;将QObject的子类移动…

【MATLAB源码-第13期】基于matlab的4ASK的误码率BER和误符号率SER理论和实际对比仿真。

1、算法描述 "4ASK" 是一种数字调制技术&#xff0c;代表4级振幅移移键控&#xff08;4-Level Amplitude Shift Keying&#xff09;调制。它是一种数字通信中常用的调制方式之一&#xff0c;用于将数字信号转换为模拟信号以便传输&#xff0c;或者将模拟信号转换为数…

【ROS2笔记三】构建ROS2功能包

3.构建ROS2功能包 文章目录 3.构建ROS2功能包3.1ROS2中包的组成部分3.2创建ROS2功能包并编写节点3.2.1使用CMake创建功能包3.2.2编写cpp节点代码 3.3编译运行节点3.4使用面向对象的方式编写ROS2节点3.5使用RCLPY编写节点Reference 3.1ROS2中包的组成部分 ROS2可以使用CMake或者…