type
status
date
slug
summary
tags
category
icon
password
Sub-item
Last edited time
Oct 15, 2023 03:57 AM
Parent item
领域
根Context
有一个emptyCtx结构实现Context的方法,基于该结构, 定义了2个全局变量为根Context。
其中:
Background
通常被用于主函数、初始化以及测试中,作为一个顶层的context
,一般我们创建的context
都是基于Background
;
TODO
是在不确定使用什么context
的时候才会使用。
valueCtx
valueCtx是带有存储key-vaule功能的Context
WithValue
WithValue
用以向context
添加键值对:添加后会形成一个Context链:

cancelCtx
其中:
done
表示一个channel
,用来表示传递关闭信号;
children
表示一个map
,存储了当前context
节点下的子节点;
err
用于存储错误信息表示任务结束的原因。
再来看一下
cancelCtx
实现的方法:可以发现
cancelCtx
类型变量其实也是canceler
类型,因为cancelCtx
实现了canceler
接口。 cancelCtx
类型的context
在调用cancel
方法时会设置取消原因,将done channel
设置为一个关闭channel
或者关闭channel
,然后将子节点context
依次取消,如果有需要还会将当前节点从父节点上移除。WithCancel
WithCancel
函数用来创建一个可取消的context
,即cancelCtx
类型的context
。WithCancel
返回一个context
和一个CancelFunc
,调用CancelFunc
即可触发cancel
操作。直接看源码:之前说到
cancelCtx
取消时,会将后代节点中所有的cancelCtx
都取消,propagateCancel
即用来建立当前节点与祖先节点这个取消关联逻辑。- 如果
parent.Done()
返回nil
,表明父节点以上的路径上没有可取消的context
,不需要处理;
- 如果在
context
链上找到到cancelCtx
类型的祖先节点,则判断这个祖先节点是否已经取消,如果已经取消就取消当前节点;否则将当前节点加入到祖先节点的children
列表。
- 否则开启一个协程,监听
parent.Done()
和child.Done()
,一旦parent.Done()
返回的channel
关闭,即context
链中某个祖先节点context
被取消,则将当前context
也取消。
这里或许有个疑问,为什么是祖先节点而不是父节点?这是因为当前
context
链可能是这样的:
当前
cancelCtx
的父节点context
并不是一个可取消的context
,也就没法记录children
。timerCtx
timerCtx
是一种基于cancelCtx
的context
类型,从字面上就能看出,这是一种可以定时取消的context
。timerCtx
内部使用cancelCtx
实现取消,另外使用定时器timer
和过期时间deadline
实现定时取消的功能。timerCtx
在调用cancel
方法,会先将内部的cancelCtx
取消,如果需要则将自己从cancelCtx
祖先节点上移除,最后取消计时器。WithDeadline
WithDeadline
返回一个基于parent
的可取消的context
,并且其过期时间deadline
不晚于所设置时间d
。- 如果父节点
parent
有过期时间并且过期时间早于给定时间d
,那么新建的子节点context
无需设置过期时间,使用WithCancel
创建一个可取消的context
即可;
- 否则,就要利用
parent
和过期时间d
创建一个定时取消的timerCtx
,并建立新建context
与可取消context
祖先节点的取消关联关系,接下来判断当前时间距离过期时间d
的时长dur
:
- 如果
dur
小于0,即当前已经过了过期时间,则直接取消新建的timerCtx
,原因为DeadlineExceeded
;
- 否则,为新建的
timerCtx
设置定时器,一旦到达过期时间即取消当前timerCtx
。
WithTimeout
与
WithDeadline
类似,WithTimeout
也是创建一个定时取消的context
,只不过WithDeadline
是接收一个过期时间点,而WithTimeout
接收一个相对当前时间的过期时长timeout
: