当前位置: 首页 > news >正文

Golang 里的 context

context 的作用

go 的编程中,常常会在一个 goroutine 中启动多个 goroutine,然后有可能在这些 goroutine 中又启动多个 goroutine。

在这里插入图片描述

如上图,在 main 函数中,启动了一个 goroutine A 和 goroutine B,然后 goroutine A 中又启动了 goroutine A1 和 goroutine A2,goroutine B 中也是。

有时候,我们可能想要取消当前的处理,这个时候自然而然的也要取消子协程的执行进程。这个时候就需要一种机制来做这件事。context 就是设计来做这件事的。

比如在 web 应用中,当子协程的某些处理时间过长的时候,我们可能想要终止下游的处理,防止协程长期占用资源。保证其他客户端的请求正常处理。

context 的不同类型

context.Background

往往用做父 context,比如在 main 中定义的 context,然后在 main 中将这个 context 传递给子协程。

context.TODO

不需要使用什么类型的 context 的时候,使用这个 context.TODO

context.WithTimeout

我们需要对子 goroutine 做一些超时控制的时候,使用这个 context,比如超过多少秒就不再做处理。

context.WithDeadline

和 context.WithTimeout 类似,只不过参数是一个 time.Time,而不是 time.Duration

context.WithCancel

如果在父 goroutine 里面需要在某些情况下取消执行的时候,可以使用这种 context。

实例

context.Background

package mainimport ("context""fmt""time"
)func main() {ctx := context.Background()go func(ctx2 context.Context) {fmt.Println("ctx2")ctx3, cancel := context.WithCancel(ctx2)go func(ctx4 context.Context) {fmt.Println("ctx4")}(ctx3)cancel()}(ctx)time.Sleep(time.Millisecond * 5)
}

在 main 入口里顶层的 context 使用 context.Background,子 goroutine 里面可以针对实际情况基于父 context 派生新的 context,比如,加入如果需要对子 goroutine 做一些条件性的取消操作,就可以像上面那样使用 ctx3, cancel := context.WithCancel(ctx2) 来基于父 context 创建一个新的 context,然后我们可以通过 cancel 来给子 goroutine 发送取消信号

注意这里的用语,这里说发送取消信号,因为事实上是否取消后续操作的控制权还是在子 goroutine 里面。但是子 goroutine 有义务停止当前 goroutine 的操作。

个人觉得一个原因是,可能子 goroutine 里面有一些清理操作需要进行,比如写个 Log 说当前操作被取消了,这种情况下直接强行取消并不是很好的选择,所以把控制权交给子 goroutine。

这一点可能在大多数文章里面可能没有提到,但是笔者觉得如果明白了这一点的话,对于理解 context 的工作机制很有帮助。

这种机制的感觉有点像是,虽然你有权力不停止当前操作,但是你有义务去停止当前的处理,给你这种权力只是为了让你有点反应时间。

context.TODO

这个就跳过吧,好像没什么好说的

context.WithTimeout

func ExampleContextWithTimeout() {// 10 毫秒超时时间// context.WithTimeout 也返回了一个 cancel 函数,但是我们这里不需要,所以忽略了。ctx, _ := context.WithTimeout(context.Background(), time.Millisecond * 10)var wg sync.WaitGroupwg.Add(1)go func(ctx context.Context) {defer wg.Done()// sleep 20 毫秒模拟耗时任务time.Sleep(time.Millisecond * 20)select {case <-ctx.Done():// 因为已经超时了,所以 ctx.Done() 返回的 channel 直接返回了,因为已经关闭了// 我们可以使用 ctx.Err() 来查看具体的原因,这里是 "context deadline exceeded"fmt.Println(ctx.Err())returndefault:fmt.Println("in goroutine")}}(ctx)wg.Wait()// Output:// context deadline exceeded
}

context.WithDeadline

func ExampleContextWithDeadline() {// 10 毫秒超时时间// context.WithDeadline 也返回了一个 cancel 函数,但是我们这里不需要,所以忽略了。ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(time.Millisecond * 10))var wg sync.WaitGroupwg.Add(1)go func(ctx context.Context) {defer wg.Done()// sleep 20 毫秒模拟耗时任务time.Sleep(time.Millisecond * 20)select {case <-ctx.Done():// 因为已经到达了 deadline,所以 ctx.Done() 返回的 channel 直接返回了,因为这个 channel 已经关闭了// ctx.Err() 同 context.WithTimeout,也是 "context deadline exceeded"fmt.Println(ctx.Err())returndefault:fmt.Println("in goroutine")}}(ctx)wg.Wait()// Output:// context deadline exceeded
}

context.WithCancel

func ExampleContextWithCancel() {// context.WithCancel 返回的第二个值是一个可以调用的函数,调用的时候子协程里面的 context 可以通过 ctx.Done() 获取到取消的信号ctx, cancel := context.WithCancel(context.Background())var wg sync.WaitGroupwg.Add(1)go func(ctx context.Context) {defer wg.Done()for {select {case <-ctx.Done():fmt.Println(ctx.Err())returndefault:fmt.Println("ExampleContextWithCancel default")}}}(ctx)cancel()wg.Wait()// Output:// context canceled
}

其实我们可以发现,context.WithTimeout 和 context.WithDeadline 也返回了一个 cancelFunc,context.WithCancel 返回的 cancelFunc 和这个的效果一样。

只不过 context.WithTimeout 和 context.WithDeadline 多提供了一个时间上的控制。

总结

  1. golang 中的 context 提供了一种父子 goroutine 之间沟通的机制

  2. context.WithTimeout、context.WithDeadline、context.WithCancel 都返回一个新的 context 和一个 cancelFunc,cancelFunc 可以用来取消子 goroutine

  3. goroutine 最终是否停止取决于子 goroutine 本身,但是我们有必要去监听 ctx.Done() 来根据父 goroutine 传递的信号来决定是否继续执行还是直接返回。

相关文章:

Golang 里的 context

context 的作用 go 的编程中&#xff0c;常常会在一个 goroutine 中启动多个 goroutine&#xff0c;然后有可能在这些 goroutine 中又启动多个 goroutine。 如上图&#xff0c;在 main 函数中&#xff0c;启动了一个 goroutine A 和 goroutine B&#xff0c;然后 goroutine A …...

PHP短链接url还原成长链接

在开发过程中&#xff0c;碰到了需要校验用户回填的短链接是不是系统所需要的&#xff0c;于是就需要还原找出短链接所对应的长链接。 长链接转短链接 在百度上搜索程序员&#xff0c;跳转页面后的url就是一个长链接。当然你可以从任何地方复制一个长链接过来。 长链接 http…...

redis原理(三)redis命令

一、字符串命令&#xff1a; 1、字符串基本操作&#xff1a; 2、自增自减 &#xff1a;如果一个值可以被解释为十进制整数或者浮点数&#xff0c;redis允许用户对这个字符串进行INCR*、DECR*操作。 &#xff08;1&#xff09;INCR key&#xff1a;将键存储的值的值加1。 &a…...

教程:在Django中实现微信授权登录

教程&#xff1a;在Django中实现微信授权登录 本教程将引导您如何在Django项目中实现微信授权登录。在本教程中&#xff0c;我们将使用自定义的用户模型User&#xff0c;并通过微信提供的API来进行用户认证。 在进行以下教程之前&#xff0c;请确保你已经在微信开放平台添加了…...

YOLOv5改进 | 主干篇 | 12月份最新成果TransNeXt特征提取网络(全网首发)

一、本文介绍 本文给大家带来的改进机制是TransNeXt特征提取网络,其发表于2023年的12月份是一个最新最前沿的网络模型&#xff0c;将其应用在我们的特征提取网络来提取特征&#xff0c;同时本文给大家解决其自带的一个报错&#xff0c;通过结合聚合的像素聚焦注意力和卷积GLU&…...

【java八股文】之计算机网络系列篇

1、TCP/IP和UDP模型 TCP/IP分层&#xff08;4层&#xff09;&#xff1a;应用层&#xff0c;传输层&#xff0c;网络层&#xff0c;数据链路层 网络的七层架构 &#xff08;7层&#xff09;&#xff1a;应用层&#xff0c;表示层&#xff0c;会话层&#xff0c;传输层&#xff…...

SpringAMQP的使用

1. 简介&#xff1a; SpringAMQP是基于RabbitMQ封装的一套模板&#xff0c;并且还利用SpringBoot对其实现了自动装配&#xff0c;使用起来非常方便。 SpringAmqp的官方地址&#xff1a;https://spring.io/projects/spring-amqp SpringAMQP提供了三个功能&#xff1a; 自动声…...

MATLAB - 使用运动学 DH 参数构建机械臂

系列文章目录 前言 一、 使用 Puma560 机械手机器人的 Denavit-Hartenberg (DH) 参数&#xff0c;逐步建立刚体树形机器人模型。在连接每个关节时&#xff0c;指定其相对 DH 参数。可视化机器人坐标系&#xff0c;并与最终模型进行交互。 DH 参数定义了每个刚体通过关节与其父…...

2024年腾讯云新用户优惠云服务器价格多少?

腾讯云服务器租用价格表&#xff1a;轻量应用服务器2核2G3M价格62元一年、2核2G4M价格118元一年&#xff0c;540元三年、2核4G5M带宽218元一年&#xff0c;2核4G5M带宽756元三年、轻量4核8G12M服务器446元一年、646元15个月&#xff0c;云服务器CVM S5实例2核2G配置280.8元一年…...

如何在原型中实现继承和多态

在JavaScript中&#xff0c;我们可以通过原型链来实现继承。以下是如何在原型中实现继承的例子&#xff1a; // 定义一个动物原型 var Animal function() {}; Animal.prototype.move function() { console.log(‘This animal can move.’); }; // 定义一个狗的原型&#xf…...

MySQL/Oracle 的 字符串拼接

目录 MySQL、Oracle 的 字符串拼接1、MySQL 的字符串拼接1.1 CONCAT(str1,str2,...) : 可以拼接多个字符串1.2 CONCAT_WS(separator,str1,str2,...) : 指定分隔符拼接多个字符串1.3 GROUP_CONCAT(expr) : 聚合函数&#xff0c;用于将多行的值连接成一个字符串。 2、Oracle 的字…...

【Java SE语法篇】10.String类

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ 文章目录 前言1. String类1.1 字符串的构造1.2 String对象的比…...

【Python】数据可视化--基于TMDB_5000_Movie数据集

一、数据准备 tmdb_5000_movie数据集下载 二、数据预处理 观察数据集合情况 import pandas as pd import ast import warnings warnings.filterwarnings(ignore) # 加载数据集 df pd.read_csv(tmdb_5000_movies.csv) # 查看数据集信息 print(df.info()) 由于原数据集包含的…...

学习Vue的插槽总结

今天学习了Vue的插槽&#xff0c;在这之前学习使用组件的使用还没有试过在父组件中给子组件插入html结构&#xff0c;今天学习的插槽正是拿来实现这一功能的&#xff0c;这也是一种组件中通信的方式&#xff0c;首先插槽分为三类&#xff1a;默认插槽、具名插槽、作用域插槽。接…...

第九篇 API设计原则与最佳实践

深入浅出HTTP请求前后端交互系列专题 第一章 引言-HTTP协议基础概念和前后端分离架构请求交互概述 第二章 HTTP请求方法、状态码详解与缓存机制解析 第三章 前端发起HTTP请求 第四章 前后端数据交换格式详解 第五章 跨域资源共享&#xff08;CORS&#xff09;&#xff1a;现代W…...

新版AndroidStudio配置maven阿里云镜像

project下的build.gradle&#xff1a; // Top-level build file where you can add configuration options common to all sub-projects/modules. // 注意jdk版本需要17以上&#xff0c;因为8.1.3的gradle需要jdk17以上 //plugins { // id com.android.application version…...

【OSG案例详细分析与讲解】之十一:【多效果的3D动画】

目录 ​​​​​​​一、【多效果的3D动画】前言 二、【多效果的3D动画】实现效果...

一道使用LinkedList和Stack解决的算法题

一、无法吃午餐的学生数量 学校的自助午餐提供圆形和方形的三明治&#xff0c;分别用数字 0 和 1 表示。所有学生站在一个队列里&#xff0c;每个学生要么喜欢圆形的要么喜欢方形的。 餐厅里三明治的数量与学生的数量相同。所有三明治都放在一个 栈 里&#xff0c;每一轮&#…...

通用外设-W25Q64

前言 一、SPI通信 二、W25Q64基初时序 1.各种命令代码 2.代码 1.写使能指令 2.读取芯片是否忙碌状态并等待 3.写入数据 4.擦除函数操作 5.读取代码 三.验证 四.擦除说明 总结 前言 在单片机中一般32K FLASH就够用了&#xff0c;但是当我们使用图片或其他大量数据时…...

Spring MVC MVC介绍和入门案例

1.SpringMVC概述 1.1.MVC介绍 MVC是一种设计模式&#xff0c;将软件按照模型、视图、控制器来划分&#xff1a; M&#xff1a;Model&#xff0c;模型层&#xff0c;指工程中的JavaBean&#xff0c;作用是处理数据 JavaBean分为两类&#xff1a; 一类称为数据承载Bean&#xf…...

技术创业中的产品迭代:从内核开发到用户中心

技术创业中的产品迭代&#xff1a;从内核开发到用户中心 产品迭代的重要性 作为一名从Linux内核开发者转型产品经理再到科技创业者的人&#xff0c;我深刻体会到产品迭代在技术创业中的重要性。一个成功的产品不是一蹴而就的&#xff0c;而是通过不断的迭代和优化逐步发展起来的…...

4大技术方案解决WarcraftHelper工具的《魔兽争霸III》兼容性与性能优化问题

4大技术方案解决WarcraftHelper工具的《魔兽争霸III》兼容性与性能优化问题 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper WarcraftHelper是一款专注…...

SEO_如何通过内容SEO获取稳定流量的关键方法

SEO:如何通过内容SEO获取稳定流量的关键方法 在当今数字化时代&#xff0c;如何通过内容SEO获取稳定流量成为了许多企业和网站运营者关注的焦点。内容SEO不仅能够提升网站的自然搜索排名&#xff0c;还能为网站带来长期的、可持续的流量。具体应该如何通过内容SEO获取稳定流量…...

怎样评估数据化管理?数据化管理如何持续改进?

在数据这个行当工作了这么多年&#xff0c;我经常会和不同公司的朋友聊天。大家刚开始做数据化管理时总是干劲十足&#xff0c;买工具、建报表、做大屏。但一两年后&#xff0c;常常陷入一种困惑&#xff1a;钱花了&#xff0c;屏挂了&#xff0c;但感觉业务还是老样子。这时候…...

计算机毕业设计:Python汽车销量全栈分析系统 Flask框架 可视化 机器学习 AI 大模型 大数据(建议收藏)✅

1、项目介绍 技术栈&#xff1a;Python语言、Flask框架、ECharts可视化库、MySQL数据库、机器学习算法 功能模块&#xff1a;数据概况展示模块多维度可视化分析模块销量预测模块生产计划辅助模块系统管控模块 项目介绍&#xff1a;本项目为汽车销量可视化分析与预测系…...

CLI为什么突然爆了?一文讲清 Skill、MCP、CLI 的真实关系

导读最近可以明显看到一个变化&#xff1a;钉钉、飞书、企业微信&#xff0c;开始陆续开放 CLI 能力 越来越多团队&#xff0c;不再只讨论提示词&#xff0c;而是在做一件更实际的事&#xff1a;让 AI 直接参与执行很多人开始有几个共通疑问&#xff1a;CLI 到底是什么Skill 和…...

揭秘AI教材写作:掌握这些技巧,用AI写教材低查重不是梦

编写教材的过程&#xff0c;总是让我踩到“慢节奏”的不少雷区。尽管框架和材料已经准备齐全&#xff0c;却在内容创作上遭遇阻碍——有时候一句话反复修改半个小时&#xff0c;心里始终觉得没说到点子上&#xff1b;而章节之间的衔接&#xff0c;绞尽脑汁也难以找到合适的表达…...

DeepSeekubernetes-1.35.3/kubernetes-1.35.3/test/utils/ktesting/examples/logging/example_test.go 源码分析

我来分析 Kubernetes 测试工具 ktesting 中的日志示例文件 example_test.go。这个文件展示了如何在 Kubernetes 测试中使用结构化日志。 文件概述 这是 Kubernetes v1.35.3 中 test/utils/ktesting 包的示例文件&#xff0c;展示了如何使用 ktesting 框架进行带有结构化日志的测…...

FIFA 23 Live Editor终极指南:10分钟掌握实时游戏修改技巧

FIFA 23 Live Editor终极指南&#xff1a;10分钟掌握实时游戏修改技巧 【免费下载链接】FIFA-23-Live-Editor FIFA 23 Live Editor 项目地址: https://gitcode.com/gh_mirrors/fi/FIFA-23-Live-Editor FIFA 23 Live Editor 是一款专为FIFA 23玩家设计的革命性实时编辑工…...

Outfit字体:如何用专业几何无衬线字体打造品牌视觉革命

Outfit字体&#xff1a;如何用专业几何无衬线字体打造品牌视觉革命 【免费下载链接】Outfit-Fonts The most on-brand typeface 项目地址: https://gitcode.com/gh_mirrors/ou/Outfit-Fonts 你是否曾为寻找一款既能体现品牌个性&#xff0c;又能在各种数字场景中完美呈现…...