专栏首页后端golang 系列:context 详解
原创

golang 系列:context 详解

摘要

在很多的 Go 开源框架里,我们经常能看到 context 的身影,它的使用场景有很多,像超时通知,取消通知都用到了 context。今天我们就来好好的认识一下它,看看 context 的相关知识和底层原理。

context 介绍

context 从它的字面量就可以看出来,是用来传递信息的。当然,这种传递并不仅仅是将数据塞给被调用者,它还能进行链式的传递,通过保存父子 context 关系,不断的迭代遍历来获取数据。

除此之外,context 还能进行链式的传播 channel 信号

我们知道 channel 是用来做 goroutine 通信使用的。这就使得 goroutine 之间能够进行链式的信号通知了,进而达到自上而下的通知效果。

例如通知所有跟 context 有血缘关系的 goroutine 进行取消动作。

Context 接口

在 Go 里并没有直接为我们提供一个统一的 context 对象,而是设计了一个接口类型的 Context。然后在这些接口上来实现了几种具体类型的 context。

这样的好处就是我们只要根据开放出来的接口定义,也能够实现属于自己的 context,进而跟官方的 context 一起配合使用。

在分析官方的几种 context 之前,我们先来看看 context 要求实现的几个接口:

  • Deadline() (deadline time.Time, ok bool)
  • Done() <-chan struct{}
  • Err() error
  • Value(key interface{}) interface{}

其中:

Deadline() 表示如果有截止时间的话,得返回对应 deadline 时间;如果没有,则 ok 的值为 false。

Done() 表示关于 channel 的数据通信,而且它的数据类型是 struct{},一个空结构体,因此在 Go 里都是直接通过 close channel 来进行通知的,不会涉及具体数据传输。

Err() 返回的是一个错误 error,如果上面的 Done() 的 channel 没被 close,则 error 为 nil;如果 channel 已被 close,则 error 将会返回 close 的原因,比如超时或手动取消。

Value() 则是用来存储具体数据的方法。

Context 类型

简单的看过 Context 接口之后,我们来看看官方的 context 类型。主要有四种,分别是 emptyCtxcancelCtxtimerCtxvalueCtx

  • emptyCtx:空的 context,实现了上面的 4 个接口,但都是直接 return 默认值,没有具体功能代码。
  • cancelCtx:用来取消通知用的 context
  • timerCtx:用来超时通知用的 context
  • valueCtx:用来传值的 context

其中:

emptyCtx 表示什么都没有的 context,一般用作最初始的 context,作为父 context 使用。像我们常见的 context.Background()返回的就是 emptyCtx。

其他类型的创建方法如下:

  • WithCancel 方法创建的是 cancelCtx 类型的 context。
  • WithDeadline 方法创建的是 timerCtx 类型的 context。
  • WithValue 方法创建的是 valueCtx 类型的 context。

上面三个方法在创建的时候都会要求传 parent context 进来,以此达到链式传递信息的目的。

Context 源码

context 的源码在 src/context/context.go 里,相信大家仔细研究,也能看到上面介绍的几个 context 对象。这边简单解释下 cancelCtxtimerCtxvalueCtx 的核心流程。

1)cancelCtx 、timerCtx(用来通知用的 context)

cancelCtx 、timerCtx 在创建的时候都会调用 propagateCancel方法,将当前的 context 挂在 父 context 下。

接着在 Done() 方法里返回了对应的 channel,让调用者能够监听 channel 信号。

当要执行取消动作时,会通过 cancel 方法关闭 channel,来达到通知 goroutine 的目的。

在 channel 关闭的同时也会对子 context 调用 cancel 方法,直到没有子 context。

cancelCtx 和 timerCtxt 不同之处就在于 cancelCtx 是手动调用 cancel 方法来触发取消通知;

而 timerCtxt 则通过 AfterFunc 超时时间来自动触发 cancel 方法。

2)valueCtx(用来传值的 context)

valueCtx 通过 key-value 形式来存储数据,当找不到 key 时,就会到 父 context 里查找,直到没有父 context:

func (c *valueCtx) Value(key interface{}) interface{} {
	if c.key == key {
		return c.val
	}
	return c.Context.Value(key) // 到父 context 里查找
}

context 注意事项

最后我们来看看在使用 context 时的几个注意事项:

  • context 的 Done() 方法往往需要配合 select {} 使用,以监听退出。undefined感兴趣的朋友可以搜一搜公众号「 阅新技术 」,关注更多的推送文章。
  • 可以的话,就顺便点个赞、留个言、分享下,感谢各位支持!undefined阅新技术,阅读更多的新知识。
  • 尽量通过函数参数来暴露 context,不要在自定义结构体里包含它。
  • WithValue 类型的 context 应该尽量存储一些全局的 data,而不要存储一些可有可无的局部 data。
  • context 是并发安全的。
  • 一旦 context 执行取消动作,所有派生的 context 都会触发取消。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

关注作者,阅读全部精彩内容

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 深入理解Golang之Context

    这篇文章将介绍Golang并发编程中常用到一种编程模式:context。本文将从为什么需要context出发,深入了解context的实现原理,以及了解如何使用...

    KevinYan
  • Android Context 详解

    在android中有两种context,一种是application context,一种是activity context,通常我们在各种类和方法间传递的是a...

    阳光岛主
  • python golang中grpc 使用示例代码详解

    由于grpc是跨语言的所以这里用golang做为示范,golang客户端代码,小编这里也踩了许多坑,最主要的是两个proto文件一定要一致,golang 中使用...

    砸漏
  • 【实践】gdb调试golang程序入门及gdb命令列表

    gdb是linux系统自带的调试器,功能十分强大,它不仅支持C/C++调试,也支持GO程序调试。

    辉哥
  • go-micro In Action

    go-micro是一个后台微服务开发框架,它提供了一个分布式系统开发所需的核心要求;其最大的特点是它是一个可插拔的架构,它对分布式系统的各个组成部分都抽象成接口...

    xiaojunzhou
  • go语言教程零基础入门到精通

    课程详细目录: ├─L001-Go语言-mp4 │ 01 Go开发1期 day1 开课介绍01.mp4 │ 02 Go开发1期 day1 ...

    码农编程进阶笔记
  • golang 系列:sync.Once 讲解

    之前提到过 Go 的并发辅助对象:WaitGroup。同样的, sync.Once 也是 Go 官方的一并发辅助对象,它能够让函数方法只执行一次,达到类似 in...

    lincoln
  • golang 系列:waitgroup 解析

    Golang 提供了简洁的 go 关键字来让开发者更容易的进行并发编程,同时也提供了 WaitGroup 对象来辅助并发控制。今天我们就来分析下 WaitGro...

    lincoln
  • golang 系列: mutex 讲解

    Go 号称是为了高并发而生的,在高并发场景下,势必会涉及到对公共资源的竞争。当对应场景发生时,我们经常会使用 mutex 的 Lock() 和 Unlock()...

    lincoln
  • Golang 高效实践之并发实践context篇

    在上篇Golang高效实践之并发实践channel篇中我给大家介绍了Golang并发模型,详细的介绍了channel的用法,和用select管理channel。...

    用户2937493
  • Golang Gin 实战(一)| 快速安装入门

    Gin 是一个非常优秀的Golang Web Framework,它不光API友好,性能也非常高,并且设计简洁,便于入门。所以它(Gin)非常受欢迎,在Gith...

    飞雪无情
  • kotlin Context使用详解

    kotlin中取消了xxxActivity.this的用法,所以我们可以在activity下新建一个Context属性——instance指向它本身。然后在其他...

    砸漏
  • golang常见知识点

    碧海长天
  • gRPC基本使用(一)--java与go之间的相互调用

    gRPC是一个高性能、开源、通用的RPC框架,面向移动和HTTP/2设计。gRPC 默认使用 protocol buffers,这是 Google 开源的一套成...

    lpe234
  • Go框架解析-Gin

    今天是我golang框架阅读系列第三篇文章,今天我们主要看看gin的框架执行流程。关于golang框架生命周期源码阅读下面是我的计划:

    用户1093396
  • 使用云函数实现消息流转

    在使用消息队列时,消息流转是常见的需求,比如消息需要从ckafka的实例转储到另一个ckafka实例。消息流转的目的通常是为了能够访问不同网络的消息队列,这是因...

    worker
  • android中Context深入详解

    以下分别通过Context认知角度,继承关系,对象创建等方面android中Context做了深入的解释,一起学习下。

    砸漏
  • 并发组件 | Go设计模式实战

    之前文章《代码组件 | Go设计模式实战》已经介绍了「组合模式」的概念,以及在业务中的使用。今天我们结合Go语言天生的并发特性,升级「组合模式」为「并发组合模式...

    用户1093396
  • TarsGo新版本发布,支持protobuf,zipkin和自定义插件

    Tars是腾讯从2008年到今天一直在使用的后台逻辑层的统一应用框架,目前支持C++,Java,PHP,Nodejs,Golang语言。该框架为用户提供了涉及到...

    腾讯开源

扫码关注云+社区

领取腾讯云代金券