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的引用,停止相关的计数器。

具身机器人内部PCB板分类与系统架构详解 本文系统梳理了机器人内部PCB板的功能架构,将其划分为5大模块:1)核心主板(含主控计算机板、实时控制板等);2)感知类PCB(视觉、听觉、触觉等);3)运动控制类PCB(伺服驱动、编码器等);4)电源与安全类PCB(电源管理、BMS等);5)通信类PCB(EtherCAT背板等)。通过人体器官类比(如大脑对应主控板、小脑对应实时控制板),详解了各模块的芯片选型、位置分布及协同关系,并给出信号/能量/指令的三流闭环示意图和典型系统参数(48V供电、1ms通信周期)。整体呈现了机器人"神经系统&qu 阅读详情

相关推荐

第四章、Isaacsim在GUI中构建机器人(3):添加摄像头和传感器

本节。

m0_47719040的博客 2495

Go Context 详解之终极无惑

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

Doublelv 的博客专栏。 8894

L298N电机驱动模块的接线使用与代码实现

#include "iostm8s208mb.h" #define u8 uint8_t #define u16 uint16_t #define u32 uint32_t typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned long uint32_t; // 关于LED灯的宏定义 #define LED2 PI_ODR_ODR2 //输出量 #define LE

Clichong 13万+

深度解密Go语言之context

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

weixin_34132768的博客 1500

大众点评爬虫实战:如何用Python绕过反爬机制获取评论数据(附完整代码)

本文深入探讨了2024年使用Python进行大众点评数据采集的实战策略。文章详细解析了现代反爬机制的核心逻辑,并提供了从构建拟人化请求会话、应对动态内容与接口加密,到工程化实践(代理调度、状态持久化)的完整解决方案与代码示例,旨在帮助数据分析师稳健获取评论数据,用于后续的文本挖掘与商业洞察。

weixin_29084111的博客 1920

Oracle集群管理-19.3升级19.18 opatchauto总结(java报错,resume oneoffs缺失目录)

t. (那个认为补丁已经打上了,但是oneoffs目录里面没有。将安装包文件的权限全部改成777.就继续执行了上述命令 ,此时使用opatch lsinv也是报错 ,在正常执行opatchauto apply。1 创建目录,存放补丁包,并赋予权限。于是使用如下命令对补丁进行回滚。

oradbm的博客 1415

go中context详解

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

qq_33369149的博客 1358

CAPL编程入门:从零开始掌握汽车通信脚本语言

本文详细介绍了CAPL编程的基础知识,从开发环境搭建到核心语法精要,再到总线通信实战和高级调试技巧。CAPL作为汽车通信脚本语言,专为CAN、LIN等网络协议设计,帮助工程师高效完成车载网络测试。通过实战案例和性能优化建议,读者可以快速掌握CAPL编程技能。

s1t2u3的博客 978

go-Context详解

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

daliucheng的博客 1718

【拼多多笔试题汇总】2024-03-24-拼多多春招笔试题

A 小镇上有个奇特的游戏。游戏开始时,A 先生准备了一排 nnn 个物品。K 小姐和卢小姐则轮流进行操作。首先,K 小姐可以选择移除至多 xxx 个物品。接着,卢小姐也可以选择移除剩余物品中的至多 yyy 个。游戏的目标是,K 小姐想尽量让剩余物品的价值之和最大化,而卢小姐则想将剩余物品的价值之和最小化。假设两人都采取最优策略,请问最后剩余物品的价值之和是多少?第一行包含五个正整数 n,m,k,x,yn, m, k, x, yn,m,k,x,y,分别表示物品的总数、K 小姐最多可移除的物品数、卢小姐最多可移

春秋招笔试突围 1万+

逆向分析顶象5代各类验证码类型的图片还原方法(附源码)

6.刷新滑块验证码图片,会进入之前的for循环断点,分析此处的代码会发现,该循环循环了处理了n字符串的值,取出n字符中的值并使用charCodeAt生成Unicode 编码,然后又调用了a函数,如果a函数返回true就会把之前生成的Unicode编码+1,a函数参数分别是c数组和Unicode取余32后的值,然后再把Unicode取余32后的值push进c数组,这里的n值为滑块碎片背景图的name。2.搜索"ranges":,会找到ranges赋值的地方,在此处代码断点,并点击跳过断点,结束此次调试。

老衲爱洗头的博客 1195

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

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

KingEasternSun的专栏 4107

人体红外传感器HC-SR501

本文记录的是如何用stm32使用HC-SR501。实验平台:野火指南者stm32f103vet6。实验现象:一旦有人体经过,LED会亮红色。HC-SR501 传感器工作原理人体都有恒定的体温,一般在 37 度,所以会发出特定波长 10UM 左右的红外线,被动式红外探头就是靠探测人体发射的 10um 左右的红外,进行工作的。人体发射的 10um 左右。

weixin_43772611的博客 1万+

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

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

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

go语言中context的用法

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

weixin_43354152的博客 1296

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

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的博客 2736

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、付费专栏及课程。

余额充值