Go的 context 包的使用

2023-10-27

背景

在父子协程协作过程中, 父协程需要给子协程传递信息, 子协程依据父协程传递的信息来决定自己的操作.
这种需求下可以使用 context 包

简介

Context通常被称为上下文,在go中,上层的协程可以将context 传给下层的协程, 来实现协程之间的信息传递, 同时下层协程也可以将context 传给更下层的协程, 来形成一张树状图.

主要方法

获得顶级上下文

首先要获得最顶级协程使用的Context

func Background() Context

Background 方法一般创建根 Context 的时候。

func TODO() Context

TODO 方法,当不清楚使用哪个上下文时,可以使用 TODO 方法。

当前协程上下文的操作

针对 Context 可以执行如下操作.

Deadline() (deadline time.Time, ok bool)

Deadline 方法返回结果有两个,第一个是截止时间,到了这个截止时间,Context 会自动取消;第二个是一个 bool 类型的值,如果 Context 没有设置截止时间,第二个返回结果是 false,如果需要取消这个 Context,就需要调用取消函数。

Done() <-chan struct{}

Done 方法返回一个只读的 channel 对象,类型是 struct{},在 goroutine 中,如果 Done 方法返回的结果可以被读取,代表父 Context 调用了取消函数。

Err() error

Err 方法返回 Context 被取消的原因。

Value(key interface{}) interface{}

Value 方法返回此 Context 绑定的值。它是一个 kv 键值对,通过 key 获取对应 value 的值

创建下级协程的Context

我们要依据父级的协程的Context创建子级协程的Context

WithCancel(parent Context) (ctx Context, cancel CancelFunc)
WithCancel 方法,基于父 Context,接收一个父 Context 参数,生成一个新的子 Context,和一个 cancel 函数,用于取消 Context。

WithDeadline(parent Context, d time.Time) (Context, CancelFunc)
WithDeadline 方法,基于父 Context,接收一个父 Context 参数,和一个截止时间的参数,生成一个新的子 Context,和一个 cancel 函数,可以使用 cancel 函数取消 Context,也可以等到截止时间,自动取消 Context。

WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
WithTimeout 方法,基于父 Context,接收一个父 Context 参数,和一个超时时间的参数,生成一个新的子 Context,和一个 cancel 函数,可以使用 cancel 函数取消 Context,也可以等到超时时间,自动取消 Context。

WithValue(parent Context, key, val interface{}) Context
WithValue 方法,基于父 Context,生成一个新的子 Context,携带了一个 kv 键值对,一般用于传递上下文信息。

场景示例

公司下班, 要领导下班后, 员工才下班, 但是员工忍耐也是有限度的, 领导老是不下班, 员工就自己走了.

package main

import (
	"context"
	"fmt"
	"time"
)

var name string

func main() {
	// 顶级Conxt, 领导
	up_context := context.Background()
	// 创建领导的下级 员工的的Context, 员工就最多加班5秒, 超过5秒领导不下班. 员工就下班了
	ctx, cancle := context.WithTimeout(up_context, time.Second*5)
	go work(ctx, "小卡拉")
	// 父线程等待3秒, 领导加班3秒
	time.Sleep(time.Second * 3)
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "领导下班了!")
	// 领导下班调用cancle(), 取消员工的 Context
	cancle()
	time.Sleep(time.Second * 5)
}

func work(ctx context.Context, name string) {
	for {
		select {
		// 看看员工的 Context 还在不在
		case <-ctx.Done():
			fmt.Println(time.Now().Format("2006-01-02 15:04:05"), name, "下班!")
			return
		default:
			fmt.Println(time.Now().Format("2006-01-02 15:04:05"), name, "加班!。")
			time.Sleep(time.Second * 1)
		}
	}
}

上面的代码中up_context 是最顶级的 Context 是使用context.Background()创建出来的, 员工的 Context对象 ctx 则是使用最顶级的up_context 并且使用WithTimeout方法创建出来的, 表示如果5秒内不调用返回的 cancel 方法, 就会自动取消, 对应员工最多等待领导五秒. 上面的执行结果是:
在这里插入图片描述
可以看到, 领导就加班了3秒, 领导一下班, 员工就下班了.

如果领导加班7秒呢, 代码改成如下

package main

import (
	"context"
	"fmt"
	"time"
)

var name string

func main() {
	// 顶级Conxt, 领导
	up_context := context.Background()
	// 创建领导的下级 员工的的Context, 员工就最多加班5秒, 超过5秒领导不下班. 员工就下班了
	ctx, cancle := context.WithTimeout(up_context, time.Second*5)
	go work(ctx, "小卡拉")
	// 父线程等待7秒, 领导加班7秒
	time.Sleep(time.Second * 7)
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "领导下班了!")
	// 领导下班调用cancle(), 取消员工的 Context
	cancle()
	time.Sleep(time.Second * 5)
}

func work(ctx context.Context, name string) {
	for {
		select {
		// 看看员工的 Context 还在不在
		case <-ctx.Done():
			fmt.Println(time.Now().Format("2006-01-02 15:04:05"), name, "下班!")
			return
		default:
			fmt.Println(time.Now().Format("2006-01-02 15:04:05"), name, "加班!。")
			time.Sleep(time.Second * 1)
		}
	}
}

执行结果如下
在这里插入图片描述
可以看到, 领导加班7秒, 员工并没有等着领导下班, 在第五秒的时候自己下班了.
在线调试:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Go的 context 包的使用 的相关文章

  • Go 中的数据竞争:为什么会在 10-11 毫秒以下发生?

    这是我运行的代码 package main import fmt time const delay 9 time Millisecond func main n 0 go func time Sleep delay n fmt Printl
  • 记录 http.ResponseWriter 内容

    Premise 我发现了类似的问题 但不适用于我的情况 因此请不要将其标记为重复 我在 Go 中有一个 HTTP 服务器 并且创建了一个中间件记录请求 响应时间 我也想记录响应 我用过httputil DumpRequest在一个名为的函数
  • K8s更改配置映射并更新应用程序日志级别

    我想更改在 K8S 上运行的 Golang 应用程序的登录配置 我在本地尝试了以下代码 它按预期工作 我正在使用 viper 来监视配置文件更改 这是带有日志配置的配置图 apiVersion v1 kind ConfigMap data
  • Google App Engine Golang 没有这样的文件或目录

    我正在用 Go 开发一个 Google App Engine 项目 并陷入了读取文件的困境 事实上 应用程序在本地运行得很好 然而 部署时 它会恐慌告诉我没有这样的文件或目录 这是我的 fileValue 方法 func fileValue
  • Golang、mysql:错误1040:连接过多

    我正在使用 github com go sql driver mysql 驱动程序 我打开一个数据库 db err sql Open mysql str 然后我有两个函数 每个函数被调用 200 次 并使用以下 mysql 代码 rows
  • java.lang.NoSuchMethodError:com.fasterxml.jackson.databind.type。使用 apache beam Spark runner 运行 go 示例时

    我想跑grades https github com apache beam tree master sdks go examples gradesapache beam go sdk 提出的示例 在一个主服务器和两个从服务器 spark2
  • go 中的属性更改通知

    如何在 go 中向多个接收器发出 属性 更改信号 类似于在 Qt 中使用通知信号定义属性的方式 例如 如果您想象有一些值需要以多种方式显示 例如进度值可以同时显示为进度条和文本 当基础值发生变化时 两者都需要更新 一种方法可能是利用chan
  • vscode 中的调试不会在断点处停止,调试器启动时显示“无法找到文件...”

    乌班图 vscode 1 62 1 去1 17 3 vscode go 扩展 v0 29 0 深入研究 v1 7 1 我是 vscode 和 Go 的新手 我有多年在 Eclipse 中调试 Java 应用程序的经验 我构建了一个小型多模块
  • Golang Appengine 项目无法构建

    我有一个使用 golang 的应用程序引擎项目 我已经大约一年没有碰过了 我现在无法让它在之前构建的机器上构建 我收到以下错误 go app builder 解析输入失败 解析器 src golang org x net internal
  • Golang - 更改 Windows 上的构建工作路径

    我正在使用 SublimeText3 GoSublime 插件 在 Windows 8 上测试简单的 Go 程序 go run v example go 在运行之前它正在内部编译 应用程序数据 本地 温度 目录 我的防病毒程序认为这是病毒并
  • GO并发编程测试

    我试图确保我的并发程序不存在以下情况 僵局 livelock 饥饿 我找到了以下工具http blog golang org race detector http blog golang org race detector 我尝试编译并运行
  • 是否支持动态变量?

    我想知道Go中是否可以动态创建变量 我在下面提供了一个伪代码来说明我的意思 我将新创建的变量存储在切片中 func method slice make type for i 0 i lt 10 i var variable i i slic
  • 按引用或按值扫描功能

    我有以下代码 statement SELECT id from source where mgmt 1 var exists string errUnique dr db QueryRow statement mgmt Scan exist
  • Golang 基础知识 struct 和 new() 关键字

    我正在学习 golang 当我阅读描述结构的章节时 我遇到了初始化结构的不同方法 p1 passport var p2 passport p3 passport Photo make byte 0 0 Name Scott Surname
  • 如何在golang模板上打印JSON?

    我需要在客户端有一个对象 所以我使用 json marshal 将其转换为 JSON 并将其打印到模板中 该对象被打印为转义 JSON 字符串 我期待它是var arr o1 o2 但它是var arr o1 o2 我知道我可以在客户端进行
  • 在 IntelliJ IDEA 中运行。多个文件和错误未定义:数据

    我想使用 IntelliJ IDE 社区版编写代码GO Go语言 我安装了正确的插件 并安装了构建应用程序所需的所有工具 我的应用程序包含以下两个文件 每个都在目录中 事件服务器 Main go Data go 如果我想使用 Run Ctl
  • 完全删除使用“go get”安装的软件包?

    我正在使用 Go 1 13 1 最新版本 我正在尝试完全删除我安装的软件包go get来自 GitHub 这go clean i
  • Go 无法推断赋值中的类型:“non-name on left side of :=”

    该片段按预期工作play golang org p VuCl OKMav http play golang org p VuCl OKMav i 10 next 11 prev i i next 然而这个几乎相同的片段给出了non name
  • Go 的范围不能超过 (类型接口 {})

    我正处于尝试将我的注意力集中在 Go 上的婴儿阶段 目前 我正在模拟一个 API 请求 该请求返回包含对象数组的 JSON 格式的字符串 我试图找出迭代每个记录并访问每个字段的最合适的方法 最终 每个字段都将写入 Excel 电子表格 但现
  • 重新插入通道导致死锁

    我有稳定的入站 作业 流 将其输入到无缓冲通道中 我有一个for range循环来迭代项目并处理它们 如果处理该项目失败 我会将项目重新插入通道中 以便稍后重试 问题是当我将项目重新插入通道时 它陷入僵局 我明白为什么会发生这种情况 处理器

随机推荐

  • 这几天心里颇不宁静,采的不是信号,而是寂寞

    原文来自微信公众号 工程师看海 这几天心里颇不宁静 今晚在院子里坐着乘凉 忽然想起往日一同攻坚的战友 在这满月的光里 该是另一番样子吧 我们制定的uV级别信号的采集方案 从原理到模拟环境测试 一切都OK 然而真正到现场采集信号时却发现 压根
  • python获取时间日期列表集合

    python获取时间日期列表集合 以前过去以后未来 安装datedays pip install datedays import datedays if name main print 测试时间 datedays getnow print
  • python-获取当前目录/上级目录/上上级目录...

    获取文件 在其他人使用你的代码时 常常因为目录层级的问题为无法运行程序 所以在引起其他模块文件时 尽量采取绝对路径的方式导 python官方建议尽量的使用绝对目录 而不是相对目录 获取当前文件的绝对路径 os path abspath fi
  • 公式微分后,为什么是偏导的相加

    二郎在研究一个公式中 会涉及分析变量对最终结果产生影响时 注 最终结果 这里确实是最后需要获得的结果 数学公式一定要和物理对应 输入放在一边 输出放在一边 否则都放在一边 就全成自变量了 变量对最终结果影响 既然涉及了分析 那么我们就先说为
  • c++中分文件编写

    c 中分文件编写 本文内容来自某视频教程 分文件格式编写格式 h中写类的成员函数声明 cpp中写成员函数实现 代码案例 所有代码写在一个文件中 如下是一段没有分文件编写的代码 即将所有代码写在一个源文件中 如图所示 以下代码实现了利用全局函
  • nginx转发wss

    做了一个tp6 swoole的项目 没找到swoole开启ssl的资料 想起以前做过转发可以实现 就新建了一个站 然后转发到swoole的端口 也能实现wss的访问 下面是配置文件 upstream wss server 127 0 0 1
  • ERP、SCM、CRM的区别和联系?

    ERP 企业资源计划 SCM 供应链管理系统 CRM 客户关系管理 是当前企业信息系统三大热门话题 无论是ERP SCM 还是CRM其根本目标都在于提高企业管理水平 提高企业核心竞争力 本文怡海软件将分别从其含义 区别 联系 集成方面进行简
  • Unity Scroll View踩坑记录

    Unity要想实现游戏中的背包滑动效果 最简单的方法就是使用ScrollView这个组件 这个组件可以实现拖动滑动的效果 如上图所示 我希望将这些Item实现背包的排版效果 第一步 现将所有的Item移到Content下 此时我们会发现部分
  • Java集合——Java8之HashMap

    一 前言 在分析jdk1 8后的HashMap源码时 发现网上好多分析都是基于之前的jdk 而Java8的HashMap对之前做了较大的优化 其中最重要的一个优化就是桶中的元素不再唯一按照链表组合 也可以使用红黑树进行存储 总之 目标只有一
  • Python爬取某短视频热点

    随着短视频的大火 不仅可以给人们带来娱乐 还有热点新闻时事以及各种知识 刷短视频也逐渐成为了日常生活的一部分 本 文以一个简单的小例子 简述如何通过Pyhton依托Selenium来爬取短视频 仅供学习分享使用 如有不足之处 还请指正 涉及
  • pyspark环境安装历史难题终于解决

    path JAVA HOME里面的D JAVA 1 jdk1 8 0 152 bin一定要全并且对应上 踩坑记录 已解决 报错 WARN ProcfsMetricsGetter Exception when trying to comput
  • 基于Java的OA系统的设计与实现

    源码及论文下载 http www byamd xyz tag java 摘 要 学习和研究办公自动化中涉及到的知识和技术是实现办公自动化系统的前提条件 通过学习研究 掌握了其中的关键技术之后 结合自身的理解 对其做出了相应的表述 同时也成功
  • 【第03例】IPD体系进阶

    目录 前言 专栏目录 具体内容 IPD 相关专栏推荐 专栏列表 作者简介 前言 今天继续来讲讲 IPD 中涉及的几个评审点 ADCP 是英文 Av
  • 彻底理解coookie、session、token

    一 发展史 1 很久很久以前 web基本上就是文档的浏览而已 既然是浏览 作为服务器 不需要记录谁在某一段时间里都浏览了什么文档 每次请求都是一个新的HTTP协议 就是请求加响应 尤其是我不用记住是谁刚刚发了HTTP请求 每个请求对我来说都
  • Linux下的Oracle连接

    1 进入Oracle su oracle 2 开启监听器 oracle localhost root lsnrctl status oracle localhost root lsnrctl start oracle localhost r
  • 微信小程序自定义 tab-bar(基于 wepy)

    背景 微信小程序提供的原生 tab bar 功能简单 样式单一 无法满足业务需求 项目中使用的是 wepy 1 x 框架 实现原理与原生类似 方案 一 使用组件 在每个Tab页引入 修改全局配置 app wpy export default
  • CloudCompare--安装和简单的使用方法

    CloudCompare 安装和简单的使用方法 CloudCompare工具是一个非常好的处理点云数据的开源工具 有个不错的框架 很多公司对该工具进行二次开发以满足公司需要 第一次使用CloudCompare感觉非常好用 有兴趣的可以多了解
  • C语言进阶知识点(持续跟新)

    还是有点儿进阶的知识点 1 大段 小段内存模型 int val 0x12345678 int p1 val char p2 char p1 printf x n p2 p2 printf x n p2 short p3 val printf
  • windows server 2012 双网卡配置

    别用route 命令 在使用最新版的windows server 2012的时候 当存在两个或者多个网段的时候 就可以采用双网卡的方式来添加和配置路由 具体的设置方法如下 网段1 192 168 0 0 网段2 192 168 1 0 20
  • Go的 context 包的使用

    文章目录 背景 简介 主要方法 获得顶级上下文 当前协程上下文的操作 创建下级协程的Context 场景示例 背景 在父子协程协作过程中 父协程需要给子协程传递信息 子协程依据父协程传递的信息来决定自己的操作 这种需求下可以使用 conte