context

216 阅读4分钟

context

www.bilibili.com/video/BV1Nb…

www.bilibili.com/video/BV1xV…

studygolang.com/articles/17…

context 可以在同一进程传递数据,但是HTTP请求需要手动做一些操作才能将值传递,比如客户端在请求服务端时在ctx里面传了一个值,但是在服务端收到ctx的时候拿着这个key是解析不到数据的

文章讲的蛮好的
1.context 可以携带key val 每次添加一对,context都会包一层,查找的时候会一层一层向上查找,直到找到

image.png 2.服务中串联日志就是将traceid作为一个key在代码中传递,最后日志中串联在一起 cloud.tencent.com/developer/a…

用来做什么

image.png

控制超时

传递kv

取消消息


总体来看,cancel() 方法的功能就是主动关闭 channel:c.done;递归地取消它的所有子节点;从父节点删除自己。达到的效果是通过关闭 channel,将取消信号传递给了它的所有子节点。goroutine 接收到取消信号的方式就是 select 语句中的读 c.done 被选中


一个很好的理解父子节点关系,理解cancelFunc 和 Done方法的 说法:

CancelFunc 和 Done 方法就像是电话的话筒听筒, CancelFunc,用来告诉管辖范围内的所有 Context 要进行自我终结,而通过监听听筒 Done 方法,我们就能听到上游父级管理者的终结命令,总之,CancelFunc 是主动让下游结束,而 Done 是被上游通知结束

一个父节点生成一个带有 Done 方法的子节点,并且返回子节点的 CancelFunc 函数句柄,底层建立的父子关联,这样父节点可以通过自己CancelFunc控制子节点,子节点也可以通过done方法监听父节点是否关闭(这是被动跟随父节点取消的逻辑)

如果请求链路上的一个方法里面只是有context作为入参,但是内部并没有使用(比如select监听ctx.Done),那么context取消也不会影响这个方法,这个方法会正常一直执行到结束,所以必须显示的监听context的状态才能受到影响

image.png

image.png

context 的实现主要有emptyCtx(作为context链路的根)cancelCtx(可以主动取消的) timerCtx(有定时功能的) timerCtx是在cancelCtx基础之上加了定时功能,也就是说他也有主动取消的功能

任何一个context不管他是什么类型只要他的父节点取消了,他也会被取消,比如一个timerctx继承自cancelctx,cancelctx主动取消了,timerctx及时没有到定时的时间也会跟着取消

func f(ctx context.Context) {
   to := time.Now()
   select {
   case <-ctx.Done():
      fmt.Println(ctx.Err(), time.Since(to))
   }
}

var closedchan = make(chan struct{})

func main() {

   pctx := context.Background()
   cctx, cancel := context.WithCancel(pctx)
   tctx, _ := context.WithTimeout(cctx, 10*time.Second)
   go f(tctx)
   time.Sleep(2 * time.Second)
   cancel()
   time.Sleep(20 * time.Second)
}

返回 context canceled 2.003239491s

创建一个cancelctx,底层会用propagateCancel方法来建立当前新建节点和父节点的关系,1.如果父节点是cancel类型的,会把这个节点放到父节点的children数组里面,这样父节点取消的时候直接在遍历数组把该节点取消;2.如果不是cancel类型,该节点就要在一个协程里面通过select监听父节点的done通道保证父节点取消的时候自己能够知道并且也调用自己的cancel方法,如果父节点一直不取消也可以监听自己的done通道,得到自己已经取消的消息就返回了,可以看出和父节点建立关系,不是把自己放在父节点的数组里面,就是自己取监听父节点的通道

如果是自己主动取消的话需要把自己从父节点的数组中删除,这样父节点取消的时候就不会再次取消这个节点了

所谓取消context就是关闭通道,timer类型的只不过是加了一个定时器,增加一个时间到了自己主动取消的功能,所以他可以跟着父节点被动取消,自己不到时间主动取消,到时间自己主动取消三种情况

done是一个只读通道,监听关闭通道关闭之后,会返回默认的零值,不再阻塞

这个视频讲的好

www.bilibili.com/video/BV1EA…