【Golang】Golang进阶系列教程--Go 语言 context 都能做什么?
文章目录
- 前言
- 核心是 Context 接口:
- 包含四个方法:
- 遵循规则
- WithCancel
- WithDeadline
- WithTimeout
- WithValue
前言
很多 Go 项目的源码,在读的过程中会发现一个很常见的参数 ctx,而且基本都是作为函数的第一个参数。
为什么要这么写呢?这个参数到底有什么用呢?带着这样的疑问,我研究了这个参数背后的故事。
开局一张图:
核心是 Context 接口:
// A Context carries a deadline, cancelation signal, and request-scoped values
// across API boundaries. Its methods are safe for simultaneous use by multiple
// goroutines.
type Context interface {// Done returns a channel that is closed when this Context is canceled// or times out.Done() <-chan struct{}// Err indicates why this context was canceled, after the Done channel// is closed.Err() error// Deadline returns the time when this Context will be canceled, if any.Deadline() (deadline time.Time, ok bool)// Value returns the value associated with key or nil if none.Value(key interface{}) interface{}
}
包含四个方法:
- Done():返回一个 channel,当 times out 或者调用 cancel 方法时。
- Err():返回一个错误,表示取消 ctx 的原因。
- Deadline():返回截止时间和一个 bool 值。
- Value():返回 key 对应的值。
有四个结构体实现了这个接口,分别是:emptyCtx, cancelCtx, timerCtx 和 valueCtx。
其中 emptyCtx 是空类型,暴露了两个方法:
func Background() Context
func TODO() Context
一般情况下,会使用 Background() 作为根 ctx,然后在其基础上再派生出子 ctx。要是不确定使用哪个 ctx,就使用 TODO()。
另外三个也分别暴露了对应的方法:
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{}) Context
遵循规则
在使用 Context 时,要遵循以下四点规则:
- 不要将 Context 放入结构体,而是应该作为第一个参数传入,命名为 ctx。
- 即使函数允许,也不要传入 nil 的 Context。如果不知道用哪种 Context,可以使用 context.TODO()。
- 使用 Context 的 Value 相关方法只应该用于在程序和接口中传递和请求相关的元数据,不要用它来传递一些可选的参数。
- 相同的 Context 可以传递给不同的 goroutine;Context 是并发安全的。
WithCancel
go复制代码func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
WithCancel 返回带有新 Done 通道的父级副本。当调用返回的 cancel 函数或关闭父上下文的 Done 通道时,返回的 ctx 的 Done 通道将关闭。
取消此上下文会释放与其关联的资源,因此在此上下文中运行的操作完成后,代码应立即调用 cancel。
举个例子:
这段代码演示了如何使用可取消上下文来防止 goroutine 泄漏。在函数结束时,由 gen 启动的 goroutine 将返回而不会泄漏。
package mainimport ("context""fmt"
)func main() {// gen generates integers in a separate goroutine and// sends them to the returned channel.// The callers of gen need to cancel the context once// they are done consuming generated integers not to leak// the internal goroutine started by gen.gen := func(ctx context.Context) <-chan int {dst := make(chan int)n := 1go func() {for {select {case <-ctx.Done():return // returning not to leak the goroutinecase dst <- n:n++}}}()return dst}ctx, cancel := context.WithCancel(context.Background())defer cancel() // cancel when we are finished consuming integersfor n := range gen(ctx) {fmt.Println(n)if n == 5 {break}}
}
输出:
2
3
4
5
WithDeadline
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)
WithDeadline 返回父上下文的副本,并将截止日期调整为不晚于 d。如果父级的截止日期已经早于 d,则 WithDeadline(parent, d) 在语义上等同于 parent。
当截止时间到期、调用返回的取消函数时或当父上下文的 Done 通道关闭时,返回的上下文的 Done 通道将关闭。
取消此上下文会释放与其关联的资源,因此在此上下文中运行的操作完成后,代码应立即调用取消。
举个例子:
这段代码传递具有截止时间的上下文,来告诉阻塞函数,它应该在到达截止时间时立刻退出。
package mainimport ("context""fmt""time"
)const shortDuration = 1 * time.Millisecondfunc main() {d := time.Now().Add(shortDuration)ctx, cancel := context.WithDeadline(context.Background(), d)// Even though ctx will be expired, it is good practice to call its// cancellation function in any case. Failure to do so may keep the// context and its parent alive longer than necessary.defer cancel()select {case <-time.After(1 * time.Second):fmt.Println("overslept")case <-ctx.Done():fmt.Println(ctx.Err())}
}
输出:
context deadline exceeded
WithTimeout
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
WithTimeout 返回 WithDeadline(parent, time.Now().Add(timeout))。
取消此上下文会释放与其关联的资源,因此在此上下文中运行的操作完成后,代码应立即调用取消。
举个例子:
这段代码传递带有超时的上下文,以告诉阻塞函数应在超时后退出。
package mainimport ("context""fmt""time"
)const shortDuration = 1 * time.Millisecondfunc main() {// Pass a context with a timeout to tell a blocking function that it// should abandon its work after the timeout elapses.ctx, cancel := context.WithTimeout(context.Background(), shortDuration)defer cancel()select {case <-time.After(1 * time.Second):fmt.Println("overslept")case <-ctx.Done():fmt.Println(ctx.Err()) // prints "context deadline exceeded"}}
输出:
context deadline exceeded
WithValue
func WithValue(parent Context, key, val any) Context
WithValue 返回父级的副本,其中与 key 关联的值为 val。
其中键必须是可比较的,并且不应是字符串类型或任何其他内置类型,以避免使用上下文的包之间发生冲突。 WithValue 的用户应该定义自己的键类型。
为了避免分配给 interface{},上下文键通常具有具体的 struct{} 类型。或者,导出的上下文键变量的静态类型应该是指针或接口。
举个例子:
这段代码演示了如何将值传递到上下文以及如何检索它(如果存在)。
package mainimport ("context""fmt"
)func main() {type favContextKey stringf := func(ctx context.Context, k favContextKey) {if v := ctx.Value(k); v != nil {fmt.Println("found value:", v)return}fmt.Println("key not found:", k)}k := favContextKey("language")ctx := context.WithValue(context.Background(), k, "Go")f(ctx, k)f(ctx, favContextKey("color"))
}
输出:
ound value: Go
key not found: color
本文的大部分内容,包括代码示例都是翻译自官方文档,代码都是经过验证可以执行的。如果有不是特别清晰的地方,可以直接去读官方文档。
相关文章:
【Golang】Golang进阶系列教程--Go 语言 context 都能做什么?
文章目录 前言核心是 Context 接口:包含四个方法:遵循规则WithCancelWithDeadlineWithTimeoutWithValue 前言 很多 Go 项目的源码,在读的过程中会发现一个很常见的参数 ctx,而且基本都是作为函数的第一个参数。 为什么要这么写呢…...

画图干货!14种uml图类型及示例
1. 什么是 UML UML 是统一建模语言的缩写。UML 图是基于 UML(统一建模语言)的图表,目的是直观地表示系统及其主要参与者、角色、动作、工件或类,以便更好地理解、更改、维护或记录信息关于系统。简而言之,UML 是一种…...

计算机视觉实验:人脸识别系统设计
实验内容 设计计算机视觉目标识别系统,与实际应用有关(建议:最终展示形式为带界面可运行的系统),以下内容选择其中一个做。 1. 人脸识别系统设计 (1) 人脸识别系统设计(必做):根据…...

振弦采集仪完整链条的岩土工程隧道安全监测
振弦采集仪完整链条的岩土工程隧道安全监测 隧道工程是一种特殊的地下工程,其建设过程及运行期间,都受到各种内外力的作用,如水压、地震、地质变形、交通荷载等,这些因素都会对隧道的安全性产生影响。因此,对隧道的安…...

NLP实战9:Transformer实战-单词预测
目录 一、定义模型 二、加载数据集 三、初始化实例 四、训练模型 五、评估模型 🍨 本文为[🔗365天深度学习训练营]内部限免文章(版权归 *K同学啊* 所有) 🍖 作者:[K同学啊] 模型结构图: &a…...
使用Vue.js和Rust构建高性能的物联网应用
物联网(IoT)应用是现代技术的重要组成部分,它们可以在各种场景中(例如智能家居,工业自动化等)提供无缝的自动化解决方案。在这篇文章中,我们将探讨如何使用Vue.js和Rust构建高性能的物联网应用。 1. 为什么选择Vue.js…...

idea调节文字大小、日志颜色、git改动信息
idea调节菜单栏文字大小: 调节代码文字大小: 按住ctrl滚动滑轮可以调节代码文字大小: 单击文件即可在主窗口上打开显示: idea在控制台对不同级别的日志打印不同颜色 : “grep console”插件 点击某一行的时候&#x…...
避免大龄程序员边缘化:如何在技术行业中保持竞争力
目录 导语持续学习和进修维护专业形象寻找适合自己的领域构建个人品牌和网络拥抱变化和创新实例结语: 导语 导语:随着科技的不断发展,技术行业的竞争日益激烈。对于那些年龄稍长的程序员来说,如何保持竞争力并避免边缘化成为了一…...

Jenkins工具系列 —— 启动 Jenkins 服务报错
错误显示 apt-get 安装 Jenkins 后,自动启动 Jenkins 服务报错。 排查原因 直接运行jenkins命令 发现具体报错log:Failed to start Jetty或Failed to bind to 0.0.0.0/0.0.0.0:8080或Address already in use 说明:这里提示的是8080端口号…...
华为数通HCIA-实验环境ensp简介
ensp 路由器:AR系列、NE系列; 模拟器中使用AR2220; 交换机:S系列、CE系列; 模拟器中使用S5700; 线缆:copper——以太网链路; serial——串行链路,在模拟器中用于模…...
SK5代理与IP代理:网络安全中的爬虫利器
一、什么是IP代理与SK5代理? IP代理: IP代理是一种允许用户通过代理服务器进行网络连接的技术。用户请求经由代理服务器中转,从而实现隐藏真实IP地址,保护用户隐私,并在一定程度上突破IP访问限制。常见的IP代理有HTTP…...

实战:Prometheus+Grafana监控Linux服务器及Springboot项目
文章目录 前言知识积累什么是Prometheus什么是Grafana怎样完成数据采集和监控 环境搭建docker与docker-compose安装docker-compose编写 监控配置grafana配置prometheus数据源grafana配置dashboardLinux Host Metrics监控Spring Boot 监控 写在最后 前言 相信大家都知道一个项目…...

[用go实现解释器]笔记1-词法分析
本文是《用go实现解释器》的读书笔记 https://malred-blogmalred.github.io/2023/06/03/ji-suan-ji-li-lun-ji-shu-ji/shi-ti/go-compile/yong-go-yu-yan-shi-xian-jie-shi-qi/go-compiler-1/#toc-heading-6http://个人博客该笔记地址 github.com/malred/malanghttp:/…...
在 spark-sql / spark-shell / hive / beeline 中粘贴 sql、程序脚本时的常见错误
一个很小的问题,简单记录一下。有时候我们会粘贴一段已经成功运行过的SQL或程序脚本,但是在spark-sql / spark-shell / hive / beeline 中执行时可能会报这样的错误: hive> CREATE EXTERNAL TABLE IF NOT EXISTS ORDERS(> Display all…...

关于视频汇聚融合EasyCVR平台多视频播放协议的概述
视频监控综合管理平台EasyCVR具备视频融合能力,平台基于云边端一体化架构,具有强大的数据接入、处理及分发能力,平台既具备传统安防视频监控的能力与服务,也支持AI智能检测技术的接入,可应用在多行业领域的智能化监管场…...

三星书画联展:三位艺术家开启国风艺术之旅
7月22日,由广州白云区文联、白云区工商联主办的“三星书画联展”,在源美术馆正式开展。本次书画展展出的艺术种类丰富,油画、国画、彩墨画、书法等作品异彩纷呈。广东省政协原副主席、农工党省委书画院名誉院长马光瑜,意大利艺术研…...

在腾讯云服务器OpenCLoudOS系统中安装nginx(有图详解)
1. 创建安装目录 2. 下载、安装、编译 进入安装目录: cd /app/soft/nginx/ 下载: wget https://nginx.org/download/nginx-1.21.6.tar.gz 解压: tar -zxvf nginx-1.21.6.tar.gz 安装插件: yum -y install pcre-devel 安装…...
大数据课程E5——Flume的Selector
文章作者邮箱:yugongshiye@sina.cn 地址:广东惠州 ▲ 本章节目的 ⚪ 了解Selector的概念和配置属性; ⚪ 掌握Selector的使用方法; 一、简介 1. 概述 1. Selector本身是Source的子组件,决定了将数据分发给哪个Channel。 2. Selector中提供了两种模式: …...

在线查看浏览器
随着网络的兴起,电影和电视剧已经成为我们生活中必不可少的乐趣。然而,像爱奇艺、优酷、腾讯、芒果等等这些平台,我们想要看好视频,需要开通VIP,虽然价格不是很高,但是我们能省则省啊,今天我就给…...

谷粒商城第七天-商品服务之分类管理下的分类的拖拽功能的实现
目录 一、总述 1.1 前端思路 1.2 后端思路 二、前端实现 2.1 判断是否能进行拖拽 2.2 收集受影响的节点,提交给服务器 三、后端实现 四、总结 一、总述 这个拖拽功能对于这种树形的列表,整体的搬迁是很方便的。但是其实现却并不是那么的简单。 …...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...