Golang Context

Golang之Context详解 golang.org/x/net/context,是golang中的一个标准库,主要作用就是创建一个上下文,实现对程序中创建的协程通过传递上下文信息来实现对协程的管理。 阅读详情
最近实现系统的分布式日志与事务管理时,在寻求所谓的全局唯一Goroutine ID无果之后,决定还是简单利用Context机制实现了基本的想法,不够高明,但是好用。于是对它当初的设计比较好奇,便有了此文。

1、What Context

Context是Golang官方定义的一个package,它定义了Context类型,里面包含了Deadline/Done/Err方法以及绑定到Context上的成员变量值Value,具体定义如下:

type Context interface {
    // 返回Context的超时时间(超时返回场景)
    Deadline() (deadline time.Time, ok bool)
    // 在Context超时或取消时(即结束了)返回一个关闭的channel
    // 即如果当前Context超时或取消时,Done方法会返回一个channel,然后其他地方就可以通过判断Done方法是否有返回(channel),如果有则说明Context已结束
    // 故其可以作为广播通知其他相关方本Context已结束,请做相关处理。
    Done() <-chan struct{}

    // 返回Context取消的原因
    Err() error
    
    // 返回Context相关数据
    Value(key interface{}) interface{}
}

那么到底什么Context?

可以字面意思可以理解为上下文,比较熟悉的有进程/线程上线文,关于Golang中的上下文,一句话概括就是:goroutine的相关环境快照,其中包含函数调用以及涉及的相关的变量值。
通过Context可以区分不同的goroutine请求,因为在Golang Severs中,每个请求都是在单个goroutine中完成的。

注:关于goroutine的理解可以移步这里。

2、Why Context

由于在Golang severs中,每个request都是在单个goroutine中完成,并且在单个goroutine(不妨称之为A)中也会有请求其他服务(启动另一个goroutine(称之为B)去完成)的场景,这就会涉及多个Goroutine之间的调用。如果某一时刻请求其他服务被取消或者超时,则作为深陷其中的当前goroutine B需要立即退出,然后系统才可回收B所占用的资源。
即一个request中通常包含多个goroutine,这些goroutine之间通常会有交互。
图片描述

那么,如何有效管理这些goroutine成为一个问题(主要是退出通知和元数据传递问题),Google的解决方法是Context机制,相互调用的goroutine之间通过传递context变量保持关联,这样在不用暴露各goroutine内部实现细节的前提下,有效地控制各goroutine的运行。
图片描述

如此一来,通过传递Context就可以追踪goroutine调用树,并在这些调用树之间传递通知和元数据。
虽然goroutine之间是平行的,没有继承关系,但是Context设计成是包含父子关系的,这样可以更好的描述goroutine调用之间的树型关系。

3、How to use

生成一个Context主要有两类方法:

3.1 )顶层Context:Background

要创建Context树,首先就是要创建根节点

// 返回一个空的Context,它作为所有由此继承Context的根节点
func Background() Context

该Context通常由接收request的第一个goroutine创建,它不能被取消、没有值、也没有过期时间,常作为处理request的顶层context存在。

3.2)下层Context:WithCancel/WithDeadline/WithTimeout

有了根节点之后,接下来就是创建子孙节点。为了可以很好的控制子孙节点,Context包提供的创建方法均是带有第二返回值(CancelFunc类型),它相当于一个Hook,在子goroutine执行过程中,可以通过触发Hook来达到控制子goroutine的目的(通常是取消,即让其停下来)。再配合Context提供的Done方法,子goroutine可以检查自身是否被父级节点Cancel:

select { 
    case <-ctx.Done(): 
        // do some clean… 
}

注:父节点Context可以主动通过调用cancel方法取消子节点Context,而子节点Context只能被动等待。同时父节点Context自身一旦被取消(如其上级节点Cancel),其下的所有子节点Context均会自动被取消。

有三种创建方法:

// 带cancel返回值的Context,一旦cancel被调用,即取消该创建的context
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) 

// 带有效期cancel返回值的Context,即必须到达指定时间点调用的cancel方法才会被执行
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) 

// 带超时时间cancel返回值的Context,类似Deadline,前者是时间点,后者为时间间隔
// 相当于WithDeadline(parent, time.Now().Add(timeout)).
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)

下面来看改编自Advanced Go Concurrency Patterns视频提供的一个简单例子:

package main

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

func someHandler() {
    // 创建继承Background的子节点Context
    ctx, cancel := context.WithCancel(context.Background())
    go doSth(ctx)

    //模拟程序运行 - Sleep 5秒
    time.Sleep(5 * time.Second)
    cancel()
}

//每1秒work一下,同时会判断ctx是否被取消,如果是就退出
func doSth(ctx context.Context) {
    var i = 1
    for {
        time.Sleep(1 * time.Second)
        select {
        case <-ctx.Done():
            fmt.Println("done")
            return
        default:
            fmt.Printf("work %d seconds: \n", i)
        }
        i++
    }
}

func main() {
    fmt.Println("start...")
    someHandler()
    fmt.Println("end.")
}

输出结果:

clipboard.png

注意,此时doSth方法中case之done的fmt.Println("done")并没有被打印出来。

超时场景:

package main

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

func timeoutHandler() {
    // 创建继承Background的子节点Context
    ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
    go doSth(ctx)

    //模拟程序运行 - Sleep 10秒
    time.Sleep(10 * time.Second)
    cancel() // 3秒后将提前取消 doSth goroutine
}

//每1秒work一下,同时会判断ctx是否被取消,如果是就退出
func doSth(ctx context.Context) {
    var i = 1
    for {
        time.Sleep(1 * time.Second)
        select {
        case <-ctx.Done():
            fmt.Println("done")
            return
        default:
            fmt.Printf("work %d seconds: \n", i)
        }
        i++
    }
}

func main() {
    fmt.Println("start...")
    timeoutHandler()
    fmt.Println("end.")
}

输出结果:

clipboard.png

4、Really elegant solution?

前面铺地了这么多。

确实,通过引入Context包,一个request范围内所有goroutine运行时的取消可以得到有效的控制。但是这种解决方式却不够优雅。

4.1 Like a virus

一旦代码中某处用到了Context,传递Context变量(通常作为函数的第一个参数)会像病毒一样蔓延在各处调用它的地方。比如在一个request中实现数据库事务或者分布式日志记录,创建的context,会作为参数传递到任何有数据库操作或日志记录需求的函数代码处。即每一个相关函数都必须增加一个context.Context类型的参数,且作为第一个参数,这对无关代码完全是侵入式的。

更多详细内容可参见:Michal Strba 的context-should-go-away-go2文章

Google Group上的讨论可移步这里。

4.2 Context isn’t for cancellation

Context机制最核心的功能是在goroutine之间传递cancel信号,但是它的实现是不完全的。

Cancel可以细分为主动与被动两种,通过传递context参数,让调用goroutine可以主动cancel被调用goroutine。但是如何得知被调用goroutine什么时候执行完毕,这部分Context机制是没有实现的。而现实中的确又有一些这样的场景,比如一个组装数据的goroutine必须等待其他goroutine完成才可开始执行,这是context明显不够用了,必须借助sync.WaitGroup。

func serve(l net.Listener) error {
        var wg sync.WaitGroup
        var conn net.Conn
        var err error
        for {
                conn, err = l.Accept()
                if err != nil {
                        break
                }
                wg.Add(1)
                go func(c net.Conn) {
                        defer wg.Done()
                        handle(c)
                }(conn)
        }
        wg.Wait()
        return err
}

5、Summary

https://golang.org/pkg/context/
https://faiface.github.io/pos...
https://juejin.im/entry/58088...
https://dave.cheney.net/2017/...
https://dave.cheney.net/2017/...
https://sites.google.com/site...

Nmap NSE脚本引擎深度解析:从自动化扫描到渗透测试实战 在网络安全领域,端口扫描是基础的信息收集手段,而自动化脚本引擎则将其提升到了深度安全评估的层面。Nmap的NSE(Nmap Scripting Engine)脚本引擎正是这样一个核心组件,它基于Lua语言,通过预定义的规则(如portrule、hostrule)在扫描的不同阶段自动执行检测任务。其技术价值在于将繁琐的手动检查工作自动化、标准化,极大地提升了渗透测试和漏洞评估的效率。在工程实践中,NSE脚本广泛应用于Web应用指纹识别、SMB共享枚举、常见服务漏洞检测等场景。例如,通过http-enum脚本可 阅读详情

相关推荐

【Golang】go语言上下文context

在Go语言中,context包是一个非常重要的工具,用于在多个goroutine之间传递请求范围的数据、取消信号以及超时控制。context包的设计初衷是为了解决在复杂的并发环境中,如何有效地管理和控制goroutine的生命周期。通过使用context,开发者可以更好地控制goroutine的取消、超时以及传递请求范围的数据。

景天科技苑 8万+

Golang中context实现原理剖析

转载: Go 并发控制context实现原理剖析 1. 前言 Golang context是Golang应用开发常用的并发控制技术,它与WaitGroup最大的不同点是context对于派生goroutine有更强的控制力,它可以控制多级的goroutine。 context翻译成中文是"上下文",即它可以控制一组呈树状结构的goroutine,每个goroutine拥有相同的上下文。 典型的使用场景如下图所示: 上图中由于goroutine派生出子goroutine,而子goroutine又继续派生新的

香烟,瓜子,矿泉水 2541

张量分解浅谈(四 Tucker 分解)

学完了SVD算法之后,我们继续回到张量几大分解的学习上来,本期学习的主要内容是张量的 Tucker 分解 以及 前面的CP分解还留下一点没有说完,正好一并补齐!后面的公式我将采用颜色标记,红色代表必须掌握,蓝色尽量掌握! 在这之前先附一张图,包含了各种运算符号的名称含义,大部分是前面说过或者使用过的: Tensor decomposition一 . Tucker 分解公式介绍和原理二 . 张量的 n-Rank 一 . Tucker 分解公式介绍和原理 我们先来看一张被使用过很多次的Trucker 分解图

欢迎来到 豪哥 的博客 1万+

golang中context包解读

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34362790的博客 186

Keil5安装多版本共存方案:实用技巧分享

分享Keil5安装过程中实现多版本共存的实用方法,解决开发环境冲突问题。通过合理配置路径与版本管理,让keil5安装更高效稳定,提升嵌入式开发体验。

weixin_42514750的博客 1525

腾讯会议+OBS虚拟摄像头:解决多人屏幕共享的终极指南(附常见问题排查)

本文详细介绍了如何利用OBS虚拟摄像头技术,解决腾讯会议中多人屏幕共享的痛点。通过将OBS作为视频混流中心,可以突破腾讯会议单屏共享的限制,实现多屏幕、多窗口内容的同步展示,并提升演示的专业度。文章涵盖了Windows与Linux双平台的配置步骤、高阶场景搭建以及常见问题(如黑屏、画中画)的排查方法,是团队协作与专业演示的实用指南。

i8j9k0l1的博客 930

golang之context使用

背景 (欢迎关注“云原生手记”微信公众号) golang中并发编程的三种实现方式:chan管道、waitGroup和Context。本篇将重点介绍context的使用,告诉大家基本的使用方式,做到会用。 Context 概念介绍 context译为上下文,golang在1.6.2的时候还没有自己的context,在1.7的版本中就把golang.org/x/net/context包被加入到了官方的库中。golang 的 Context包,是专门用来处理多个goroutine之间与请求域的数据、取消信号、截

学习学习再学习 3136

5分钟搞定Unity+Visual Studio开发环境配置(含C#游戏开发工作负载)

本文提供了一份详细的Unity与Visual Studio开发环境配置指南,帮助开发者在5分钟内完成C#游戏开发工作负载的设置。从Unity Hub安装到Visual Studio关键组件选择,再到常见问题排查,全面覆盖环境搭建的各个环节,显著提升游戏开发效率。

weixin_29014237的博客 247

Golang context包的使用

Go 中的 context 包在与 API 和慢处理交互时可以派上用场,特别是在生产级的 Web 服务中。在这些场景中,您可能想要通知所有的 goroutine 停止运行并返回。在 Go 语言中 context 包允许您传递一个 "context" 到您的程序。 Context 如超时或截止日期(deadline)或通道,来指示停止运行和返回。例如,如果您正在执行一个 web 请求或运行一个系统命...

weixin_42117918的博客 3417

解决TextMeshPro在AB打包中的字体冗余问题:源码修改全记录

本文详细介绍了如何解决TextMeshPro在AB打包中的字体冗余问题,通过源码改造和工程实践优化Unity项目的性能。内容包括资源加载路径重构、AB打包策略优化及运行时加载方案,有效减少包体体积和构建时间,提升内存效率。

weixin_42558257的博客 184

信息化建设项目前期方案编制4:如何画好四张图

这里探讨以下具体的总体设计操作层面的工作。总体设计主要是完成四张图,总体架构(逻辑架构)、应用架构、网络拓扑、系统部署图。对于一些单一的系统,往往总体架构和应用架构可以合一。网络拓扑画好了,系统部署图也可以省略。有些项目还会在这之外,有所谓的技术架构图。对应用系统、数据存储等各个部分各自用的主要技术、服务等,给出总体设计图。但通常来说,这四张图在一个中等规模(200~500万,软件...

Leonardo的博客 4634

[Golang] Context

什么是context、如何创建context、context怎么衍生4个With函数

好兄弟起把大狙 1512

基于多智能体架构的AI自动化渗透测试平台PentAGI部署与实战

自动化渗透测试是网络安全领域提升效率、应对复杂威胁的关键技术。其核心原理在于通过程序化脚本或智能系统模拟攻击者行为,对目标系统进行安全评估。该技术能显著降低人工重复劳动,实现7x24小时持续监控与测试,其价值在于将安全专家从繁琐的扫描、信息收集中解放出来,专注于高级威胁分析与策略制定。在实际应用中,自动化渗透测试广泛应用于企业安全自评估、红蓝对抗演练及DevSecOps流程。本文聚焦于一个名为PentAGI的先进平台,它采用多智能体(Multi-Agent)系统架构,集成了知识图谱和向量数据库,实现了从侦察

weixin_30294295的博客 603

go context获取get参数_走进Golang之Context的使用

我们为什么需要 Context 的呢?我们来看看看一个 HTTP 请求的处理:请求示意例子大概意思是说,有一个获取订单详情的请求,会单独起一个 goroutine 去处理该请求。在该请求内部又有三个分支 goroutine 分别处理订单详情、推荐商品、物流信息;每个分支可能又需要单独调用DB、Redis等存储组件。那么面对这个场景我们需要哪些额外的事情呢?三个分支 goroutine 可...

weixin_39752215的博客 1948

【RTD】二分法查找和分段线性插值算法在RTD中应用

二分法查找和分段线性插值算法在RTD中的典型应用。

只要思想不滑坡,想法总比问题多。 2368

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Golang 里的 context

golang 中的 context 提供了一种父子 goroutine 之间沟通的机制context.WithTimeout、context.WithDeadline、context.WithCancel 都返回一个新的 context 和一个 cancelFunc,cancelFunc 可以用来取消子 goroutinegoroutine 最终是否停止取决于子 goroutine 本身,但是我们有必要去监听 ctx.Done() 来根据父 goroutine 传递的信号来决定是否继续执行还是直接返回。

rubys007的博客 2740

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Golang 之context用法

文章目录1. context2. context.go2.0 结构图2.1 Context interface2.2 emptyCtx2.3 cancelCtx2.4 valueCtx2.5 timerCtx3. 使用示例3.1 WithCancel3.2 WithDeadline3.3 WithTimeout3.4 WithValue 1. context Golang 中的context 是Go语言在 golang1.7 发布时新增的标准包 目的是增强Golang开发中并发控制技术 简单来讲当一个服

Gcaptain 9142

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

golang-context详解

cancel 其实就是通过chan + select进行提前中断返回如果没有context,携程之间怎么做这些交互呢?肯定也能做跨线程通讯如共享内存,pipe等等都可以做到,但是就需要开发者对通讯设计建模、规划数据同步方式等,这里面还需要考虑内存管理和死锁问题。context相当于程序已经提供了这样一套设计方案(CSP),可以很方便使用。也符合golang的“简单”哲学。在跨线程场景下,相当于提供了官方的解决方案。

S_ZaiJiangHu的博客 1774

Go最全Golang Context 的使用指南_golang context 使用(1),作为Golang开发程序员

上述代码将创建一个新的 Context,该 Context 在 5 秒钟之后自动取消。同时,我们也创建了一个cancel函数,用于在函数退出时显式地取消 Context。

2401_84904597的博客 539

深入解析Golang之Context

​context是什么 context翻译成中文就是上下文,在软件开发环境中,是指接口之间或函数调用之间,除了传递业务参数之外的额外信息,像在微服务环境中,传递追踪信息traceID, 请求接收和返回时间,以及登录操作用户的身份等等。本文说的context是指golang标准库中的context包。Go标准库中的context包,提供了goroutine之间的传递信息的机制,信号同步,除此之外还有超时(timeout)和取消(cancel)机制。概括起来,Context可以控制子goroutine的运行,

数据小冰的博客 5028

Golang Context详解

在Go 1.7版本中引入了上下文(context)包,用于在并发编程中管理请求范围的数据、控制生命周期、处理取消信号和超时等。context在Go中具有重要的作用,特别是在并发编程和网络编程中,因此context通常会作为各个函数和方法的首个入参。

2021dragon的博客 3701

Golang context 万字解析实现原理

如果 parent 没有实现afterFuncer接口,则启动一个协程,通过多路复用的方式监控 parent 状态,如果终止,则同时终止子 context,并把parent 的 err传递给子context,如果孩子终止则直接跳过,因为不影响parent。如果parent 是 cancelCtx 的类型,则加锁,并将子 context 添加到 parent 的 children map 当中,假如以后父context取消,可以直接用children map 取消所有的子context。

qq_29647593的博客 1847

Golang context.Context

我们今天主要讨论的是 context 包中的函数和 Context 类型, 该包中的函数都是用于产生新的 Context 类型值的, Context 类型是一个可以帮助我们实现多 goroutine 协作流程的同步工具, 不但如此, 我们还可以通过此类型的值传达撤销信号或传递数据。Context 类型的实际值大体上分为三种, 即: 根 Context 值、可撤销的 Context 值和含数据的 Context 值。......

云满笔记 1143

GoLang之context如何被取消(4)

GoLang之context如何被取消(4)

weixin_52690231的博客 2061

golang mysql context_Go语言实战笔记(二十)| Go Context

《Go语言实战》读书笔记,未完待续,欢迎扫码关注公众号flysnow_org或者网站http://www.flysnow.org/,第一时间看后续笔记。觉得有帮助的话,顺手分享到朋友圈吧,感谢支持。控制并发有两种经典的方式,一种是WaitGroup,另外一种就是Context,今天我就谈谈Context。什么是WaitGroupWaitGroup以前我们在并发的时候介绍过,它是一种控制并发的方式,...

weixin_30978427的博客 335

go切片的深入学习以及context库的使用

1.如果期望容量大于当前容量的两倍就会使用期望容量;2.如果当前切片的长度小于 1024 就会将容量翻倍;3.如果当前切片的长度大于 1024 就会每次增加 25% 的容量,直到新容量大于期望容量;

qq_63728673的博客 1464
上一篇: Golang Http Server源码阅读
下一篇: golang定时器
phpduang
博客等级 码龄10年 9粉丝 17原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值