在golang控制并发(sync.WaitGroup和context.Context)中,我们有讲到context的作用及简单使用,现在扩展开来讲讲context还有哪些别的东西

Context 接口

Context 的接口定义的比较简洁,我们看下这个接口的方法。

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

这个接口共有 4 个方法,了解这些方法的意思非常重要,这样我们才可以更好的使用他们。

Deadline 方法是获取设置的截止时间的意思,第一个返回式是截止时间,到了这个时间点,Context 会自动发起取消请求;第二个返回值 ok==false 时表示没有设置截止时间,如果需要取消的话,需要调用取消函数进行取消。

Done 方法返回一个只读的 chan,类型为 struct{},我们在 goroutine 中,如果该方法返回的 chan 可以读取,则意味着 parent context 已经发起了取消请求,我们通过 Done 方法收到这个信号后,就应该做清理操作,然后退出 goroutine,释放资源。

Err 方法返回取消的错误原因,因为什么 Context 被取消。

Value 方法获取该 Context 上绑定的值,是一个键值对,所以要通过一个 Key 才可以获取对应的值,这个值一般是线程安全的。

以上四个方法中常用的就是 Done 了,如果 Context 取消的时候,我们就可以得到一个关闭的 chan,关闭的 chan 是可以读取的,所以只要可以读取的时候,就意味着收到 Context 取消的信号了,以下是这个方法的经典用法。

  func Stream(ctx context.Context, out chan<- Value) error {for {v, err := DoSomething(ctx)if err != nil {return err}select {case <-ctx.Done():return ctx.Err()case out <- v:}}}

Context 接口并不需要我们实现,Go 内置已经帮我们实现了 2 个,我们代码中最开始都是以这两个内置的作为最顶层的 partent context,衍生出更多的子 Context。

var (background = new(emptyCtx)todo       = new(emptyCtx)
)func Background() Context {return background
}func TODO() Context {return todo
}

一个是 Background,主要用于 main 函数、初始化以及测试代码中,作为 Context 这个树结构的最顶层的 Context,也就是根 Context。

一个是 TODO,它目前还不知道具体的使用场景,如果我们不知道该使用什么 Context 的时候,可以使用这个。

它们两个本质上都是 emptyCtx 结构体类型,是一个不可取消,没有设置截止时间,没有携带任何值的 Context。

type emptyCtx intfunc (*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 interface{}) interface{} {return nil
}

这就是 emptyCtx 实现 Context 接口的方法,可以看到,这些方法什么都没做,返回的都是 nil 或者零值。

Context 的继承衍生
有了如上的根 Context,那么是如何衍生更多的子 Context 的呢?这就要靠 context 包为我们提供的 With 系列的函数了。

func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{}) Context
这四个 With 函数,接收的都有一个 partent 参数,就是父 Context,我们要基于这个父 Context 创建出子 Context 的意思,这种方式可以理解为子 Context 对父 Context 的继承,也可以理解为基于父 Context 的衍生。通过这些函数,就创建了一颗 Context 树,树的每个节点都可以有任意多个子节点,节点层级可以有任意多个。

WithCancel 函数,传递一个父 Context 作为参数,返回子 Context,以及一个取消函数用来取消 Context。 WithDeadline 函数,和 WithCancel 差不多,它会多传递一个截止时间参数,意味着到了这个时间点,会自动取消 Context,当然我们也可以不等到这个时候,可以提前通过取消函数进行取消。

WithTimeoutWithDeadline 基本上一样,这个表示是超时自动取消,是多少时间后自动取消 Context 的意思。

WithValue 函数和取消 Context 无关,它是为了生成一个绑定了一个键值对数据的 Context,这个绑定的数据可以通过 Context.Value 方法访问到,后面我们会专门讲。

大家可能留意到,前三个函数都返回一个取消函数 CancelFunc,这是一个函数类型,它的定义非常简单。

type CancelFunc func()

这就是取消函数的类型,该函数可以取消一个 Context,以及这个节点 Context下所有的所有的 Context,不管有多少层级。

WithValue传递元数据
通过 Context 我们也可以传递一些必须的元数据,这些数据会附加在 Context 上以供使用。

var key string = "name"func main() {ctx, cancel := context.WithCancel(context.Background())//附加值valueCtx := context.WithValue(ctx, key, "【监控1】")go watch(valueCtx)time.Sleep(10 * time.Second)fmt.Println("可以了,通知监控停止")cancel()//为了检测监控过是否停止,如果没有监控输出,就表示停止了time.Sleep(5 * time.Second)
}func watch(ctx context.Context) {for {select {case <-ctx.Done()://取出值fmt.Println(ctx.Value(key), "监控退出,停止了...")returndefault://取出值fmt.Println(ctx.Value(key), "goroutine监控中...")time.Sleep(2 * time.Second)}}
}

在前面的例子,我们通过传递参数的方式,把 name 的值传递给监控函数。在这个例子里,我们实现一样的效果,但是通过的是 Context 的 Value 的方式。

我们可以使用 context.WithValue 方法附加一对 K-V 的键值对,这里 Key 必须是等价性的,也就是具有可比性;Value 值要是线程安全的。

这样我们就生成了一个新的 Context,这个新的 Context 带有这个键值对,在使用的时候,可以通过 Value 方法读取 ctx.Value(key)。

记住,使用 WithValue 传值,一般是必须的值,不要什么值都传递。(原因待查

Context 使用原则

不要把 Context 放在结构体中,要以参数的方式传递
以 Context 作为参数的函数方法,应该把 Context 作为第一个参数,放在第一位。
给一个函数方法传递 Context 的时候,不要传递 nil,如果不知道传递什么,就使用 context.TODO
Context 的 Value 相关方法应该传递必须的数据,不要什么数据都使用这个传递
Context 是线程安全的,可以放心的在多个 goroutine 中传递

参考资料:
深入理解Golang之context
面向信仰编程讲上下文 Context

context.Context相关推荐

  1. android this context,Android應用開發中關於this.context=context的理解

    在Android應用開發中,有的類里面需要聲明一個Context的成員變量,然后還需要在該類的構造函數中加上this.context=context;這行代碼.為什么要這么寫呢?不寫不行么? 先看下面 ...

  2. Hadoop中Context类的作用和Mapper<LongWritable, Text, Text, LongWritable>.Context context是怎么回事【笔记自用】

    问题导读: 1.Context能干什么? 2.你对Context类了解多少? 3.Context在mapreduce中的作用是什么? 下面我们通过来源码,来得到Context的作用: 下面主要对Set ...

  3. mybatis-plus 错误java.lang.NoClassDefFoundError: org/apache/velocity/context/Context

    https://blog.csdn.net/qq_39609151/article/details/82855305 mybatis-plus 错误java.lang.NoClassDefFoundE ...

  4. MybatisPlus报错: org.apache.velocity.context.Context(已解决)

    MybatisPlus报错: org.apache.velocity.context.Context(已解决) 报错如图所示: 原因是缺少了依赖,解决方案如下: pom.xml文件当中加入veloci ...

  5. Go context.Context的学习

    一.前言 Golang context是Golang应用开发常用的并发控制技术,它与WaitGroup最大的不同点是context对于派生goroutine有更强的控制力,它可以控制多级的gorout ...

  6. Golang context.Context

    这里填写标题 1. Golang context.Context 1.1. 内容前导 1.2. 基础知识 1.2.1. Context 接口 1.2.2. 顶层 Context 1.2.3. 子 Co ...

  7. mybatis-plus自动生成的时候报错java.lang.NoClassDefFoundError: org/apache/velocity/context/Context

    当使用mybatisplus的代码自动生成的时候报错 09:02:44.188 [main] DEBUG com.baomidou.mybatisplus.generator.AutoGenerato ...

  8. Context context = getApplicationContext()

    使用getApplicationContext 取得的是当前app所使用的application,这在AndroidManifest中唯一指定.意味着,在当前app的任意位置使用这个函数得到的是同一个 ...

  9. Exception in thread “main“ java.lang.NoClassDefFoundError: org/apache/velocity/context/Context at c

    11:41:33.067 [main] DEBUG com.baomidou.mybatisplus.generator.AutoGenerator - ======================= ...

最新文章

  1. tomcat会自动解压webapps目录下的war包
  2. 31 天重构学习笔记索引
  3. git for windows的下载地址
  4. 面试进阶之字符串常量池
  5. PersonGraphDataSet近十万的开放人物关系图谱项目
  6. WSL2构建android10+kernel源码适配pixel
  7. ASP.net校友录毕业设计(源代码+论文+开题报告+答辩PPT)ASP.NET小型证券术语解释及翻译系统的设计与开发(源代码+论文)
  8. CODESYS学习心得(持续更新)
  9. linux系统双显卡切换显卡驱动,Ubuntu 14.04 安装 Nvidia 私有驱动并进行双显卡切换...
  10. 赤峰市田家炳中学2021高考成绩查询,2021年常州各高中高考成绩排名及放榜最新消息...
  11. 文明与征服李世民最强阵容推荐
  12. 基于matlab的系统校正,基于MATLAB的控制系统校正_毕业论文
  13. MVCC如何实现数据库读已提交和可重复读这两种隔离级别?
  14. 什么是百度竞价包年?竞价包年骗局揭露
  15. 清华大学06届 计算机王煜,2006年科研成果一览表
  16. idea的注释老是从行首开始
  17. Microsoft.Office.Interop.Excel的用法以及利用Microsoft.Office.Interop.Excel将web页面转成PDF
  18. 动态网页和静态网页的差异
  19. 企业辛迪加:德鲁克日志之五月十八日
  20. 安徽大学计算机系统作业答案4,安徽大学计算机教学部试题及标准答案

热门文章

  1. 904. 水果成篮(c++)
  2. Linux 内存映射之文件映射
  3. log4j之additivity
  4. 最新全国省市(简称) json文件
  5. 中国大学MOOC C语言程序设计(大连理工大学) 课后编程题 第三周题解(个人向仅供参考)
  6. php保留两位小叔_PHP价格格式化,保留两位小数
  7. new Date() 获取本月天数、获取本月的最后一天日期
  8. js中定时器与延时器的用法
  9. 解决document.form.submit()对象不支持此属性或方法
  10. 优质的计算机专业书籍有哪些?