go context用法详解

Go语言Context全解析 文章目录说明背景介绍责任与边界知识点的准备与复习标准库的默认实现使用场景链路信息取消超时控制部分源码解读参考链接 说明 此篇博客只介绍 go语言 context 包的用法以及使用场景,适度的做一些源码分析,但不会太深入。go语言的context包设计非常巧妙,非常值得学习,在学习的时候,不要只盯着一个东西学,而要学会迁移学习。比如在这个包当中涉及到了一些别的知识,比如time包的用法,go语言channel的用法,等等。学完此节,相信你会对我刚刚提到的那些知识点又有新的领悟。 背景介绍 在go语言编写的服务 阅读详情

转发自 作者kingeasternsun  https://studygolang.com/articles/10155?fr=sidebar

本文主要基于官方文档Go Concurrency Patterns: Context以及视频Advanced Go Concurrency Patterns的学习而得。

背景

在go服务器中,对于每个请求的request都是在单独的goroutine中进行的,处理一个request也可能设计多个goroutine之间的交互, 使用context可以使开发者方便的在这些goroutine里传递request相关的数据、取消goroutine的signal或截止日期。

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 方法在Context被取消或超时时返回一个close的channel,close的channel可以作为广播通知,告诉给context相关的函数要停止当前工作然后返回。

当一个父operation启动一个goroutine用于子operation,这些子operation不能够取消父operation。下面描述的WithCancel函数提供一种方式可以取消新创建的Context.

Context可以安全的被多个goroutine使用。开发者可以把一个Context传递给任意多个goroutine然后cancel这个context的时候就能够通知到所有的goroutine。

Err方法返回context为什么被取消。

Deadline返回context何时会超时。

Value返回context相关的数据。

继承的Context

BackGround

// Background returns an empty Context. It is never canceled, has no deadline,
// and has no values. Background is typically used in main, init, and tests,
// and as the top-level Context for incoming requests.
func Background() Context

BackGound是所有Context的root,不能够被cancel。

WithCancel

// WithCancel returns a copy of parent whose Done channel is closed as soon as
// parent.Done is closed or cancel is called.
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)

WithCancel返回一个继承的Context,这个Context在父Context的Done被关闭时关闭自己的Done通道,或者在自己被Cancel的时候关闭自己的Done。
WithCancel同时还返回一个取消函数cancel,这个cancel用于取消当前的Context。

视频Advanced Go Concurrency Patterns中的第一个关于WithCancel的样例代码,本人有所修改

package main

import (
    "context"
    "log"
    "os"
    "time"
)

var logg *log.Logger

func someHandler() {
    ctx, cancel := context.WithCancel(context.Background())
    go doStuff(ctx)

//10秒后取消doStuff
    time.Sleep(10 * time.Second)
    cancel()

}

//每1秒work一下,同时会判断ctx是否被取消了,如果是就退出
func doStuff(ctx context.Context) {
    for {
        time.Sleep(1 * time.Second)
        select {
        case <-ctx.Done():
            logg.Printf("done")
            return
        default:
            logg.Printf("work")
        }
    }
}

func main() {
    logg = log.New(os.Stdout, "", log.Ltime)
    someHandler()
    logg.Printf("down")
}

结果

E:\wdy\goproject>go run context_learn.go
15:06:44 work
15:06:45 work
15:06:46 work
15:06:47 work
15:06:48 work
15:06:49 work
15:06:50 work
15:06:51 work
15:06:52 work
15:06:53 down

withDeadline withTimeout

WithTimeout func(parent Context, timeout time.Duration) (Context, CancelFunc)
WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).

WithTimeout 等价于 WithDeadline(parent, time.Now().Add(timeout)).

对上面的样例代码进行修改

func timeoutHandler() {
    // ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
    // go doTimeOutStuff(ctx)
    go doStuff(ctx)

    time.Sleep(10 * time.Second)

    cancel()

}

func main() {
    logg = log.New(os.Stdout, "", log.Ltime)
    timeoutHandler()
    logg.Printf("end")
}

输出

15:59:22 work
15:59:24 work
15:59:25 work
15:59:26 work
15:59:27 done
15:59:31 end

可以看到doStuff在context超时的时候被取消了,ctx.Done()被关闭。
将context.WithDeadline替换为context.WithTimeout

func timeoutHandler() {
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    // ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
    // go doTimeOutStuff(ctx)
    go doStuff(ctx)

    time.Sleep(10 * time.Second)

    cancel()

}

输出

16:02:47 work
16:02:49 work
16:02:50 work
16:02:51 work
16:02:52 done
16:02:56 end

根据视频Advanced Go Concurrency Patterns5分48秒处的代码编写doTimeOutStuff替换doStuff

func doTimeOutStuff(ctx context.Context) {
    for {
        time.Sleep(1 * time.Second)

        if deadline, ok := ctx.Deadline(); ok { //设置了deadl
            logg.Printf("deadline set")
            if time.Now().After(deadline) {
                logg.Printf(ctx.Err().Error())
                return
            }

        }

        select {
        case <-ctx.Done():
            logg.Printf("done")
            return
        default:
            logg.Printf("work")
        }
    }
}

func timeoutHandler() {
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    // ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
    go doTimeOutStuff(ctx)
    // go doStuff(ctx)

    time.Sleep(10 * time.Second)

    cancel()

}

输出:

16:03:55 deadline set
16:03:55 work
16:03:56 deadline set
16:03:56 work
16:03:57 deadline set
16:03:57 work
16:03:58 deadline set
16:03:58 work
16:03:59 deadline set
16:03:59 context deadline exceeded
16:04:04 end

context deadline exceeded就是ctx超时的时候ctx.Err的错误消息。

搜索测试程序

完整代码参见官方文档Go Concurrency Patterns: Context,其中关键的地方在于函数httpDo

func httpDo(ctx context.Context, req *http.Request, f func(*http.Response, error) error) error {
    // Run the HTTP request in a goroutine and pass the response to f.
    tr := &http.Transport{}
    client := &http.Client{Transport: tr}
    c := make(chan error, 1)
    go func() { c <- f(client.Do(req)) }()
    select {
    case <-ctx.Done():
        tr.CancelRequest(req)
        <-c // Wait for f to return.
        return ctx.Err()
    case err := <-c:
        return err
    }
}

httpDo关键的地方在于

    select {
    case <-ctx.Done():
        tr.CancelRequest(req)
        <-c // Wait for f to return.
        return ctx.Err()
    case err := <-c:
        return err
    }

要么ctx被取消,要么request请求出错。

WithValue

func WithValue(parent Context, key interface{}, val interface{}) Context

参见搜索程序userip中的代码
关键的代码如下:

// NewContext returns a new Context carrying userIP.
func NewContext(ctx context.Context, userIP net.IP) context.Context {
    return context.WithValue(ctx, userIPKey, userIP)
}

// FromContext extracts the user IP address from ctx, if present.
func FromContext(ctx context.Context) (net.IP, bool) {
    // ctx.Value returns nil if ctx has no value for the key;
    // the net.IP type assertion returns ok=false for nil.
    userIP, ok := ctx.Value(userIPKey).(net.IP)
    return userIP, ok
}

go doc中的信息

The WithCancel, WithDeadline, and WithTimeout functions take a Context (the
parent) and return a derived Context (the child) and a CancelFunc. Calling
the CancelFunc cancels the child and its children, removes the parent's
reference to the child, and stops any associated timers.

里面需要注意的就是 调用CancelFunc会取消child以及child生成的context,取出父context对这个child的引用,停止相关的计数器。

springcloud+nacos+gateway+oauth2小聚会 在微服务工程中,Nacos作为目前主流的注册中心和配置中心,Spring Cloud Gateway作为目前主流的网关,下面引入spring security+oauth2+jwt作为认证和授权中心,进行简单的聊聊。 阅读详情

相关推荐

从收音机到Arduino:手把手教你用BJT三极管搭建一个简易音频放大器(附电路图与元件清单)

本文详细介绍了如何使用BJT三极管搭建简易音频放大器,涵盖电路原理、元件选择、设计步骤及调试技巧。通过实践项目帮助电子爱好者深入理解BJT的放大特性,并提供与Arduino结合的扩展应用方案,适合创客和DIY玩家。

aitie1479的博客 439

Go Context 详解之终极无惑

Go 1.7 标准库引入 Context,中文名为上下文,是一个跨 API 和进程用来传递截止日期、取消信号和请求范围的值的接口。Deadline()返回一个完成工作的截止时间,表示上下文应该被取消的时间。如果 ok==false 表示没有设置截止时间。Done()返回一个 Channel,这个 Channel 会在当前工作完成时被关闭,表示上下文应该被取消。如果无法取消此上下文,则 Done 可能返回 nil。多次调用 Done 方法会返回同一个 Channel。Err()

Doublelv 的博客专栏。 8894

医学影像分割入门:为什么U-Net至今仍是肝脏CT肿瘤分割的‘首选’?

本文探讨了U-Net在肝脏CT肿瘤分割中的持久优势,分析了其轻量化设计、对称架构和跳跃连接如何完美适配医学影像的小样本、高精度需求。通过对比实验和实战建议,揭示了U-Net在肝脏肿瘤分割任务中超越新模型的根本原因,并提供了PyTorch实现和部署技巧。

weixin_38166931的博客 518

深度解密Go语言之context

Go 语言的 context 包短小精悍,非常适合新手学习。不论是它的源码还是实际使用,都值得投入时间去学习。 这篇文章依然想尝试全面、深入地去研究。文章相比往期而言,整体不长,希望你看完可以有所收获! 什么是 context Go 1.7 标准库引入 context,中文译作“上下文”,准确说它是 goroutine 的上下文,包含 goroutine 的运行状态、环境、现场等信息。 conte...

weixin_34132768的博客 1500

UE4项目迁移指南:如何无缝导入外部.uasset文件并保持材质关联

本文详细解析了将外部.uasset文件无缝导入UE4项目的专业方法。针对手动复制文件时常见的材质关联丢失问题,提供了使用引用查看器进行诊断和修复的实用技巧,并推荐使用引擎内置的“迁移”功能确保资源依赖关系的完整性,帮助开发者高效整合项目资源。

t8u9v0的博客 1046

Android逆向实战:通过smali/baksmali动态注入DEX逻辑

本文详细介绍了在无源码条件下对Android应用进行动态逻辑注入的实战方法。通过使用smali和baksmali工具对DEX文件进行反编译、修改与重打包,实现在目标方法中插入自定义代码(如日志打印),并分享了定位目标、处理寄存器、避免常见错误的实用技巧与避坑指南。

weixin_29008691的博客 364

go中context详解

这里需要注意的是,go中处理请求每一次都会有一个context(翻译叫做上下文,这个名字就很能凸显context的作用,在go的程序中单个的goroutine只能算作处理逻辑的单元,因为对于一个请求可能会经过多个goroutine来处理,当进行到某一步的时候需要知道我进行到这一步时之前步骤对于一些值或者逻辑的处理,所以这个名字很恰当)对于很多熟悉go的人来说context是一个简单的功能点,但是一般简单的东西也有很多值得关注学习的地方,本篇本章就是针对context的设计及目标进行思考及剖析。

qq_33369149的博客 1358

Quartus的Signal Tap II的使用技巧

Signal Tap II全称Signal Tap II Logic Analyzer,是第二代系统级调试工具,它集成在Quartus II软件中,可以捕获和显示实时信号,是一款功能强大、极具实用性的FPGA片上调试工具软件。传统的FPGA板级调试是由外接的逻辑分析仪连接到FPGA的控制引脚,将内部引号引出至引脚I/O上,接着进行板级调试。

qq_37624854的博客 5899

go-Context详解

Context是一个很特殊的接口,在go里面主要承担的责任是在边界(方法,线程等)传递上下文,这些上下文包括需要有几个注意点。

daliucheng的博客 1718

基于Dify实现对Excel的数据分析

在dify部署完成后,大家就可以基于此进行各种应用场景建设,目前dify支持聊天助手(包括对话工作流)、工作流、agent等模式的场景建设,我们在日常工作中经常会遇到各种各样的数据清洗、格式转换处理、数据统计成图等数据分析工作,本次主要基于对话工作流模式对Excel文件、csv文件进行解析处理,并进行成图等数据分析工作。主要用到的插件有LLM节点,文档提取器、参数提取器、自定义代码节点、echart插件等。实现解析Excel数据,经过上述不同节点的处理分析流程,最终实现数据统计图展示。

hhue2007的专栏 1万+

如何学习总线技术

如何学习总线技术 以形象生动的比喻来描绘了总线技术的基本思想,指出了总线的基本分类和总线传输的基本原理,以及在学习过程中应当掌握的最基本的知识,对初学者有起到抛砖引入的作用。 0引言   如果一座只能容一个人来往的独木桥,两端的人都想要过桥,为了不拥挤、阻塞,那我们就得采取有效的办法。比如规定某段时间哪端的人过桥,另一端的人就等着该他过桥的时间段的到来,同时也还可以规定人多时要按先来后到或年

ce123的技术博客 8528

服务器开发利器golang context用法详解

背景 Context结构 继承的Context BackGround WithCancel withDeadline withTimeout 搜索测试程序 WithValue go doc中的信息 后记

KingEasternSun的专栏 4107

解决TexStudio编写LaTeX论文引用文献问题:正文引用处出现[?],参考文献也不显现

当我们利用LaTeX编写论文时,可能会出现引用参考文献时正文引用处出现?号,肯能的原因及解决方案如下: 问题一 忘记在\end{document}前面放\bibliographystyle{样式}和\bibliography{参考文献bib文件名}: \bibliographystyle{plain} \bibliography{sample} 其中, LaTeX 标准选项及其样式共有以下8种: plain,按字母的顺序排列,比较次序为作者、年度和标题. unsrt,样式同plain,只是按照引用的先后

左手の明天的博客 9529

Golang Context 用法

go process(ctx) // 错误:未处理ctx.Done()fmt.Println("查询超时:", ctx.Err())fmt.Println("收到终止信号,停止工作")fmt.Println("工作中...")1. **生命周期控制**:管理goroutine树的生命周期。1. **参数传递**:context应作为函数的第一个参数。4. **超时控制**:设置截止时间(Deadline)3. **值传递**:安全地在调用链中传递元数据。3. **资源释放**:始终调用cancel函数。

wwwenhx的博客 488

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

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

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

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

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

go语言中context的用法

Context是 Go 语言中非常重要的一个概念,它主要用于跨多个函数或 goroutine 传递取消信号超时控制截止时间和请求范围数据。在并发编程中,Context提供了更好的控制和管理,尤其是当你需要在多个 goroutine 之间传递状态或进行资源清理时。

weixin_43354152的博客 1296

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Go 语言 context 用法全面解析

子协程在执行过程中,通过监听 ctx.Done() 通道来接收取消信号。在 Go 的并发编程中, context 是一个极为重要的工具,它为我们在处理多个 goroutine 以及复杂的请求处理流程时,提供了一种有效的控制手段。在实际的 Go 并发编程中,熟练掌握 context 的这些用法,并根据具体的业务需求合理选择和组合使用,能够帮助我们更好地管理 goroutine 的生命周期、控制操作的执行时间和范围以及实现请求范围内数据的共享,从而构建出更加高效、健壮且易于维护的并发程序。

进击的Blazor 1039

go context 四种衍生用法

go context 四种衍生用法 我在这就不具体的讲解他的用法\含义\以及低层原理,大家可以百度搜索学习,我在这直接上代码,简单实例 WithCancel func main() { //根context background := context.Background() ctx, cancel := context.WithCancel(background) go watch(ctx, "【监控1】") go watch(ctx, "【监控2】") go watch(ctx, "【监控

shunuanwei的博客 514

golang中 Context的四大用法

超时时间适合用于任务需要在调用后一定时间内完成的场景, 而截止时间适合用于任务需要在指定时间之前完成的场景。两者都用于控制任务的执行时间,但适用场景有所不同。

g821228的博客 435

Go语言Context (ctx)的基础概念与用法

ctx字面意思上下文,是golang中特有的一种语法,几乎每一个程序中都会通篇传递着一个ctx。而一些框架又对其进行二次封装,诸如Gin框架中的。因此此次进行ctx的学习并记录。

Ws_Te47的博客 2735

golang mysql context_服务器开发利器golang context用法详解

背景在go服务器中,对于每个请求的request都是在单独的goroutine中进行的,处理一个request也可能设计多个goroutine之间的交互, 使用context可以使开发者方便的在这些goroutine里传递request相关的数据、取消goroutine的signal或截止日期。Context结构// A Context carries a deadline, cancelatio...

weixin_29483277的博客 328

golang context用法详解

  最初接触golang http源码的时候就发现有一个比较特别的package,顺便把它的源码给看了下,了解下它的工作原理,并且在后面学习etcd源码的时候发现几乎每一个回调相关的函数都会有一个ctx参数,今天闲下来了这么常用的东西还是做下笔记为好。   context包在golang源码的golang.org/x/net/context目录下,context主要用在结束若干个相互具有父子(主...

FAS ------ 一颗好奇心,一页好代码! 4885

go context的用法

背景 在go服务器中,对于每个请求的request都是在单独的goroutine中进行的,处理一个request也可能设计多个goroutine之间的交互, 使用context可以使开发者方便的在这些goroutine里传递request相关的数据、取消goroutine的signal或截止日期。 Context是Golang官方定义的一个package,它定义了Context类型,里面包含了Deadline/Done/Err方法以及绑定到Context上的成员变量值Value context结构 // A

lanseali的博客 611

Go Context 的正确用法

但需注意,键应自定义类型以避免冲突,且数据应为请求相关的元信息(如TraceID),而非业务数据。例如,微服务调用时,通过父Context派生子Context并设置超时,可防止级联阻塞。关键点在于:超时Context必须作为参数传递给所有依赖调用,且超时时间应逐层递减,确保上游优先退出。在Go语言开发中,Context是处理并发控制、超时管理和请求链路跟踪的核心工具。掌握Context的正确用法,能显著提升Go程序的并发安全性和可维护性。**避免Context误用****实现超时与截止控制**

nhxtwp_017的博客 220

Golang 的context用法

Golang 中的 context 是Go 语言在 golang 1.7 发布时新增的标注包。目的是增强Golang 开发中并发控制技术简单来说当一个服务启动时候,可能由此服务派生出多层级的goroutine ,但本质上来讲每个层级的goroutine 都是平行调度使用,不存在goroutine的父子关系,当其中一个goroutine执行的任务被取消了或者处理超时了,那么其他被启动起来的goroutine 都应该迅速退出,另外多个多层的goroutine 想传递请求域的数据该如何处理?

weixin_52621900的博客 616
上一篇: emacs 常用用法
下一篇: golang:interface{}类型测试
乃不知有汉
博客等级 码龄17年 96粉丝 73原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值