Golang-context理解



注:以下内容是看小徐的公众号及B站学习源码做的笔记,个人理解,仅供参考

golang为何设计context?

有并发特性的语言中,都会有一种说法:创建异步线程或者携程的时候,如果不知道它们什么时候终止就不应该创建它。背后意思就是不能滥用并发,要做到心中有数的并发控制。 所以有context最主要目的就是用来做并发控制。

代码上理解原理

协程的执行是一条链路,context的设计也是基于链路来实现层级结构中传递取消信号和其他数据的。所以cancelctx,timectx,valuectx这三个类的结构体中,都有一个嵌入父亲context的字段。
核心数据结构:context接口,有4个API。后面的几个类实现这4个API。
image.png
Done 返回的是只读channel,用于传递取消信息。

空context类

context.Background() 或者context.TODO() 返回 emptyCtx类型实例(空context)。空context也实现了接口的4个API的框架,不过是空实现。

cancelCtx类

image.png
嵌入context结构体。因为cancelctx不能作为context链路的根
Context作为并发链路上的公用数据结构,所以有锁
Done()API需要返回一个只读channel,所以有一个通道
子context 用一个map管理
返回的err

cancelctx类实现了done、err、value这3个方法,前两个比较实现比较简单,就是加锁然后返回通道或者err。 value方法的实现上埋了一个伏笔,判断cancelctxkey是否= 传入的key,如果是就返回当前ctx
image.png

.withcancelctx方法

image.png
返回派生context 以及一个 cancel函数(可以终止该派生context以及该context的所有子context)
如何做到父亲cancle后,孩子能cancel的单向取消链路? 这就是withcancel()方法中调用的 propagate方法(父ctx, 子ctx)实现的。
在这个方法中会判断父ctx是否是cancelctx,如果是,withcancel创建的派生ctx会被加入到cancelctx类的子ctx的map中。 如果不是cancelctx,但是又有cancel()能力,则会创建一个守护协程去监听父Ctx何时取消,一旦父ctx取消,派生的cancelctx就取消。

如何判断父ctx是不是cancalctx?这就收回之前说的cancelctx实现的value方法中的cancelctx独有的一个协议,判断key是否== cancelctxkey,如果是,就返回ctx本身。progatecancel()中调用了一个parentctx()方法,其中就调用了value方法,从而判断父ctx是否是cancelctx,是的话就加入父ctx的子ctx map中,不是的话就启用守护协程。

withcancel()返回的cancel()方法。
cancel方法要实现的主要是三点(其实根据cancelctx类也能猜测要做的是什么): 补充当前ctx的err; 修改channel把channel关闭,从而让上游ctx能通过Done()方法捕捉到到当前ctx取消的信号;取消当前ctx,并且有义务将子ctxmap中的ctx全部都取消掉
另外,在cancel中还会调用之前withcancel生产派生ctx时的 progatecancel中的parentctx方法来判断父ctx是否为cancelctx,如果是,还需要在父ctx的map中删除当前ctx

timerCtx类

继承自cancelctx类,在cancel类的基础上封装,新增了timer用于定时终止ctx,另外新增deadline字段用于返回timerctx的过期时间。
image.png
方法:
timerCtx.Deadline()方法,context接口中的deadline 这个API只在timerCtx中实现,用来展示过期时间。

timerCtx.cancel()方法,复用了cancelCtx的cancel方法,细节上补充了一个停止timer计时。因为直接调用cancel了,就没必要浪费资源了。

timerCtx.WithTimeout()方法,实现上,在父ctx不空的情况下,首先判断给定的过期时间是不是比父ctx还晚,如果是,那就直接返回cancelCtx以及cancel闭包(如果父ctx有deadline,并且结束时间比新ctx的结束时间还早就没必要把新ctx设定为timerCtx了,父ctx过期的时候会因为链路问题把子Ctx一并取消掉)。 如果不是,生成已给timerCtx,并且通过progatecancel方法将父、子ctx的cancel进行同步,保证cancel的单向传递。启用time.until(d)进行计时

valueCtx类

image.png
嵌入context,另外有一个kv对。

方法上:
valueCtx.Value()方法,判断传入key是否==当前valueCtx的key,如果是则返回对应的val,如果不是,则在一个for循环里面通过Ctx.Context取父context不断向上进行匹配。 直到找到key。
value.WithValue()方法, 返回一个valueCtx。这个ValueCtx的第一个字段Context被调用该方法的parent赋值了。image.png

image.png

  • 25
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值