概述

    context是Go中广泛使用的程序包,由Google官方开发,在1.7版本引入。它用来简化在多个go routine传递上下文数据、(手动/超时)中止routine树等操作,比如,官方http包使用context传递请求的上下文数据,gRpc使用context来终止某个请求产生的routine树。每个Context应该视为只读的,通过WithCancel、WithDeadline、WithTimeout和WithValue函数可以基于现有的一个Context(称为父Context)派生出一个新的Context(称为子Context)。其中WithCancel、WithDeadline和WithTimeout函数除了返回一个派生的Context以外,还会返回一个与之关联CancelFunc类型的函数,用于关闭Context。通过调用CancelFunc来关闭关联的Context时,基于该Context所派生的Context也都会被关闭,并且会将自己从父Context中移除,停止和它相关的timer。

核心接口

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

 根据如上接口显示对每个方法介绍

  • Done会返回一个channel,当该context被取消的时候,该channel会被关闭,同时对应的使用该context的routine也应该结束并返回。
  • Context中的方法是协程安全的,这也就代表了在父routine中创建的context,可以传递给任意数量的routine并让他们同时访问。
  • Deadline会返回一个超时时间,routine获得了超时时间后,可以对某些io操作设定超时时间。
  • Value可以让routine共享一些数据,当然获得数据是协程安全的。

在请求处理的过程中,会调用各层的函数,每层的函数会创建自己的routine,是一个routine树。所以,context也应该反映并实现成一棵树。

创建context

在创建context时会通过context.Background函数的返回值是一个空的context,作为树的根结点。并且提供4个常用函数去创建其子节点。

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 interface{}, val interface{}) Context

 需要注意的是每个函数都会返回一个CancelFunc。调用CancelFunc对象将撤销对应的Context对象,这样父结点的所在的环境中,获得了撤销子节点context的权利,当触发某些条件时,可以调用CancelFunc对象来终止子结点树的所有routine。

我们在子集中可以通过 cxt.Done()是否为空来判断。

select {
case <-cxt.Done():
// do some cleaning and return
}

WithDeadlineWithTimeoutWithCancel多了一个时间参数,它指示context存活的最长时间。如果超过了过期时间,会自动撤销它的子context。所以context的生命期是由父context的routine和deadline共同决定的。

WithValue返回parent的一个副本,该副本保存了传入的key/value,而调用Context接口的Value(key)方法就可以得到val。注意在同一个context中设置key/value,若key相同,值会被覆盖。

示例

package main

import (
"fmt"
"time"
"golang.org/x/net/context"
) func main() {
ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*5)
ctx = context.WithValue(ctx, "Test", "123456")
defer cancelFunc() if t, ok := ctx.Deadline(); ok {
fmt.Println(time.Now())
fmt.Println(t.String())
}
go func(ctx context.Context) {
fmt.Println(ctx.Value("Test"))
for {
select {
case <-ctx.Done():
fmt.Println(ctx.Err())
return
default:
continue
}
}
}(ctx)
time.Sleep(time.Second * 3)
}

 


最新文章

  1. Revit API 获取某墙上洞口的尺寸和位置
  2. 你都认识下面这些参数么?【Camera】
  3. C#产生不重复的随机数并生成随机文件名
  4. SQL Server调优系列基础篇 - 索引运算总结
  5. propertychange input change
  6. Server(Iocp)的那些烦恼
  7. Oracle.DataAccess.Client.OracleCommand”的类型初始值设定项引发异常。
  8. jetbrains的JetBrains PyCharm 2018.3.1破解激活到2100年(最新亲测可用)
  9. 关于GitHub
  10. docker gitlab安装
  11. Hadoop 入门
  12. 给radio加自己的样式(图片)
  13. element-ui 点击行如何获取table的行索引
  14. ASP.NET对无序列表批量操作的三种方法
  15. selenium测试(Java)--下拉框(二十一)
  16. word问题禁止宏
  17. android中自定义view构造函数ContentItemView(Context context, AttributeSet paramAttributeSet)的用处
  18. [原创]Spring Boot + Mybatis 简易使用指南(一)基础环境搭建
  19. drools入门示例
  20. 【springmvc+mybatis项目实战】杰信商贸-7.生产厂家新增

热门文章

  1. openjudge1.2
  2. 何时使用 django 以及何时不用?
  3. 你真的知道Java中boolean类型占用多少个字节吗?
  4. Redis Streams 介绍
  5. thymeleaf和freemarker比较
  6. Chrome:不受信任的证书----openssl签发带Subject Alternative Name的证书
  7. Jenkins 发布项目到远程服务器上
  8. 面试突击(五)——Java常用集合
  9. pipenv使用学习
  10. 阿里巴巴Java开发手册(华山版)