go context学习

server/2025/3/10 18:48:01/

    • 1.Context接口
    • 2.emptyCtx
    • 3.Deadline()方法
    • 4.Done()方法
    • 5.Err方法
    • 6.Value方法()
    • 7.contex应用场景
    • 8.其他context方法

1.Context接口

Context接口只有四个方法,以下是context源码。

type Context interface {Deadline() (deadline time.Time, ok bool)Done() <-chan struct{}Err() errorValue(key any) any
}

2.emptyCtx

context接口源码中有两个对外的实现,context.Background()和context.TODO(),都返回一个emptyCtx。

Background()和TODO()可以看作是emptyCtx的别名,用法如下:

  • Background(),当我们自己创建一个context,可以用context.Background();
  • TODO(),当我们调用一个方法,方法有个参数是context,我们又没有context可以传,就可以传context.TODO()。
func Background() Context {return backgroundCtx{}
}
func TODO() Context {return todoCtx{}
}
type backgroundCtx struct{ emptyCtx }
type todoCtx struct{ emptyCtx }type emptyCtx struct{}
func (emptyCtx) Deadline() (deadline time.Time, ok bool) {return
}
func (emptyCtx) Done() <-chan struct{} {return nil
}
func (emptyCtx) Err() error {return nil
}
func (emptyCtx) Value(key any) any {return nil
}

3.Deadline()方法

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

返回这个context的deadline(结束时间)和ok,如果context设置了deadline,ok=ture,反之ok=false
如下可以看到,context如果没有设置deadline,则默认时间是“0001-01-01 00:00:00 +0000 UTC”

func TestContextDeadline(t *testing.T) {ctx := context.Background()deadline, ok := ctx.Deadline()fmt.Println(deadline)     //输出,0001-01-01 00:00:00 +0000 UTCfmt.Print(ok)  // 输出,false
}

下面这是设置了时间的,可以看到dealine是当前时间加10秒,

func TestContextDeadline(t *testing.T) {fmt.Println(time.Now())ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))deadline, ok := ctx.Deadline()fmt.Println(deadline)fmt.Println(ok)
}
输出:
2025-03-09 15:58:20.2027155 +0800 CST m=+0.001014101
2025-03-09 15:58:30.2080898 +0800 CST m=+10.006388401
true

如里对一个子contex设置的deadline时间比已有的contex大(就是比父context大),则不会生效

func TestContextDeadline2(t *testing.T) {fmt.Println(time.Now())ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))fmt.Println(ctx.Deadline())ctx2, _ := context.WithDeadline(ctx, time.Now().Add(15*time.Second))fmt.Println(ctx2.Deadline())
}
输出:
2025-03-09 18:11:08.6194041 +0800 CST m=+0.001034701
2025-03-09 18:11:18.6251276 +0800 CST m=+10.006758201 true
2025-03-09 18:11:18.6251276 +0800 CST m=+10.006758201 true

ctx2的dealine并没有加15秒,而是和父deadline一样。
如果子deadline比父小,子deadline就会生效,并且父deadline不受影响。如下:

func TestContextDeadline2(t *testing.T) {fmt.Println(time.Now())ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))fmt.Println(ctx.Deadline())ctx2, _ := context.WithDeadline(ctx, time.Now().Add(5*time.Second))fmt.Println(ctx2.Deadline())fmt.Println(ctx.Deadline())
}
输出:
2025-03-09 18:16:08.5541102 +0800 CST m=+0.003605801
2025-03-09 18:16:18.5612081 +0800 CST m=+10.010703701 true
2025-03-09 18:16:13.5612081 +0800 CST m=+5.010703701 true
2025-03-09 18:16:18.5612081 +0800 CST m=+10.010703701 true

4.Done()方法

Done() <-chan struct{}

Done()返回一个chan,当调用<-ctx.Done(),会一直阻塞,如果ctx的deadline时间到了,才能从chan返回

func TestContextDone(t *testing.T) {fmt.Println(time.Now())ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))deadline, ok := ctx.Deadline()fmt.Println(deadline)fmt.Println(ok)<-ctx.Done()   //Done()会一直阻塞等到deadline时间到了才结束fmt.Println(time.Now())    //当前时间加了10秒,因为<-ctx.Done() 阻塞了10秒
}
输出:
2025-03-09 16:02:27.898926 +0800 CST m=+0.001548101
2025-03-09 16:02:37.9048716 +0800 CST m=+10.007493701
true
2025-03-09 16:02:37.9052627 +0800 CST m=+10.007884801

注意context.WithDeadline()方法还返回一个cancel

func TestContextDeadline(t *testing.T) {fmt.Println(time.Now())ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))deadline, ok := ctx.Deadline()fmt.Println(deadline)fmt.Println(ok)cancel()    //cancel会让context立刻结束,<-ctx.Done() ///Done()不会阻塞fmt.Println(time.Now())
}
输出:
2025-03-09 17:25:36.815137 +0800 CST m=+0.001292801
2025-03-09 17:25:46.8209512 +0800 CST m=+10.007107001
true
2025-03-09 17:25:36.8209512 +0800 CST m=+0.007107001

如果ctx没有设置deadline,ctx.Done()返回nil

func TestContextDone(t *testing.T) {ctx := context.Background()fmt.Println(ctx.Done())   //输出nil
}

5.Err方法

Err() error

返回一个错误,有两种错误
1.deadline时间到了
2.ctx被cancel了

以下是deadline时间到了的示例:

  • ctx设置10秒后结束 ,第一次调用ctx.Err(),输出nill(因为还没到10秒,ctx还没结束)
  • 等到11秒后,ctx.Err()输出了结束原因context deadline exceeded(deadline到时间结束)。

如果ctx结束了,调用ctx.Err()返回的结果一样,下面调用了三次,结果一样。

func TestContextErr(t *testing.T) {fmt.Println(time.Now())ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))fmt.Println(ctx.Err())time.Sleep(11 * time.Second)fmt.Println(time.Now())fmt.Println(ctx.Err())fmt.Println(ctx.Err())fmt.Println(ctx.Err())
}
输出:
2025-03-09 16:17:04.7489444 +0800 CST m=+0.001009401
<nil>
2025-03-09 16:17:15.7551472 +0800 CST m=+11.007212201
context deadline exceeded
context deadline exceeded
context deadline exceeded

以下是cancel示例

func TestContextDeadline(t *testing.T) {fmt.Println(time.Now())ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))deadline, ok := ctx.Deadline()fmt.Println(deadline)fmt.Println(ok)cancel()      //调用了cancel()<-ctx.Done() fmt.Println(time.Now())fmt.Println(ctx.Err())
}
输出:
2025-03-09 17:54:11.8989047 +0800 CST m=+0.001138201
2025-03-09 17:54:21.9048333 +0800 CST m=+10.007066801
true
2025-03-09 17:54:11.9048333 +0800 CST m=+0.007066801
context canceled

6.Value方法()

Value(key any) any

就是往context存了key/value形式的数据,然后通过Value()方法取出这个值。

func TestContextValue(t *testing.T) {ctx := context.WithValue(context.Background(), "name", "daniel")fmt.Println(ctx.Value("name"))     //输出daniel
}

7.contex应用场景

context是多线程安全的,常用于并发控制技术,在不同的goroutine之间同步请求特定的数据、取消信号以及处理请求的dealine(截止日期)。
通知其他goroutine结束
如下所示,设置findUser()方法只能查找用户10秒钟,10秒后强制结束这个goroutine。

func findUser(ctx context.Context, id int) {//输出ctx结束时间fmt.Println(ctx.Deadline())for {//模拟根据id查找用户time.Sleep(2 * time.Second)select {case <-ctx.Done():fmt.Println("ctx被取消,查找结束")fmt.Println(ctx.Err())fmt.Println(time.Now())returndefault:fmt.Println("正在查找中...")}}
}func TestContext(t *testing.T) {fmt.Println(time.Now())ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))go findUser(ctx, 100)time.Sleep(20 * time.Second)
}
输出:
2025-03-09 16:46:05.7818671 +0800 CST m=+0.000000001
2025-03-09 16:46:15.7892368 +0800 CST m=+10.007369701 true
正在查找中...
正在查找中...
正在查找中...
正在查找中...
ctx被取消,查找结束
context deadline exceeded
2025-03-09 16:46:15.7919931 +0800 CST m=+10.010126001

8.其他context方法

cotext还有很多其他方法,相当于返回context的一个特定实现(context内部的实现),各有不同的功能。
在这里插入图片描述
ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(10*time.Second))
比如上面这个会返回一个带deadline方法,其实是返回一个timerCtx,里面记下了deadline,
可以看到这些方法里面都有c.m.lock()方法,所以context是多线程安全的。
context源码也比较简单,有兴趣自行看看源码。
在这里插入图片描述
timerCtx开头是小写的,也就是context内部的实现
在这里插入图片描述
context.WithDeadlineCause()也可以自定义一个cause

func TestContextDeadlineCause(t *testing.T) {ctx, _ := context.WithDeadlineCause(context.Background(),time.Now().Add(10*time.Second), errors.New("my error"))fmt.Println(context.Cause(ctx))time.Sleep(11 * time.Second)  //context.Cause(ctx)先输出nill,等结事时间到了才输出真正的causefmt.Println(context.Cause(ctx))
}
输出
<nil>
my error

http://www.ppmy.cn/server/174000.html

相关文章

【AI论文】GEN3C: 基于3D信息的全球一致视频生成技术,实现精确相机控制

摘要&#xff1a;我们提出了GEN3C&#xff0c;这是一种具有精确相机控制和时间3D一致性的视频生成模型。早期的视频模型已经能够生成逼真的视频&#xff0c;但它们往往利用很少的3D信息&#xff0c;从而导致诸如物体突然出现或消失等不一致现象。即便实现了相机控制&#xff0c…

【由技及道】量子构建交响曲:Jenkinsfile流水线的十一维编程艺术【人工智障AI2077的开发日志008】

摘要&#xff1a;当代码提交触发时空涟漪&#xff0c;当构建流水线穿越量子维度——欢迎来到自动化构建的终极形态。本文将揭示如何用Jenkinsfile编写量子构建乐章&#xff0c;让每次代码提交都成为跨维度交响乐的音符。 动机&#xff1a;构建系统的量子哲学 “主人啊&#xff…

电路的一些设计经验

这个C37在这里位于AMS1117-3.3稳压器的输入端。这个是作为输入滤波电容&#xff0c;有助于平滑输入电压&#xff0c;减少输入电压的纹波和噪声&#xff0c;从而提高稳压器LDO的稳定性。 电容器储存电荷&#xff0c;当输入电压出现小的拨动或者纹波时&#xff0c;电容器可以释放…

mysql视图

视图&#xff08;View&#xff09;是数据库中一种虚拟的表&#xff0c;它是基于 SQL 查询的结果集。视图实际上并不存储数据&#xff0c;而是根据定义的查询语句动态地生成结果。通过视图&#xff0c;可以简化复杂查询操作、隐藏数据表的结构&#xff0c;以及提高数据安全性。 …

基于Spring Boot的健美操评分管理系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

每天五分钟深度学习PyTorch:向更深的卷积神经网络挑战的ResNet

本文重点 ResNet大名鼎鼎,它是由何恺明团队设计的,它获取了2015年ImageNet冠军,它很好的解决了当神经网络层数过多出现的难以训练的问题,它创造性的设计了跳跃连接的方式,使得卷积神经网络的层数出现了大幅度提升,设置可以达到上千层,可以说resnet对于网络模型的设计具…

aws(学习笔记第三十二课) 深入使用cdk(API Gateway + event bridge)

文章目录 aws(学习笔记第三十二课) 深入使用cdk学习内容&#xff1a;1. 使用aws API Gatewaylambda1.1. 以前的练习1.2. 使用cdk创建API Gateway lambda1.3. 确认cdk创建API Gateway lambda 2. 使用event bridge练习producer和consumer2.1. 代码链接2.2. 开始练习2.3. 代码部…

react拖曳组件react-dnd的简单封装使用

分享原因 由于项目中需要使用拖曳组件(需求:全局&#xff0c;跨组件&#xff0c;跨数据)&#xff0c;我选择了react-dnd 概念 React DnD 是一组 React 高阶组件&#xff0c;我们在使用的时候只需要将目标元素进行包裹&#xff0c;就可以实现目标元素具有拖动或接受拖动的功能。…