goland WithCancel分析
Posted 安然_随心
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了goland WithCancel分析相关的知识,希望对你有一定的参考价值。
文章目录
WithCancel 返回context ,该context 是父context 的一个完整的拷贝,该新的context 有自己新的Done Channel。
WithCancel 有两个核心的功能:
- 当父context 关闭的时候,需要将本cancel context 关闭;
- 调用 cancel context 返回的cancel func 的时候,需要将本cancel context 和 cancel context 的子 context 取消关闭。
从下面三个部分来说明:
- context 接口;
- 怎么做到父context 关闭, 新的cancel context 关闭;
- 如何关闭 cancel context 的子context
1. context 接口
type Context interface
//返回什么时候,该context 所表示的任务到期(如果没有设置到期时间,则 ok =fasle).函数具有幂等性
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct
Err() error
Value(key interface) interface
可通过context 的Done接口判定该任务是否 完成 或取消。如果Done 返回一个 被关闭的通道/或者nil
Err(): 返回被关闭的原因。
2. 怎么做到父context 关闭, 新的cancel context 关闭
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
c := newCancelCtx(parent)
propagateCancel(parent, &c)
return &c, func() c.cancel(true, Canceled)
cancel context 在propagateCancel 中实现此功能,实现的方式如下:
- 在新建 cancel context 时,如果 父context 的done 通道关闭,则父context 无法被取消了;
- 如果父 context 是系统 cancelCtx 、timerCtx 类型,且父 context 已经关闭了,则现在就可以直接关闭 新的cancel context 了;
- 如果父 context 是系统 cancelCtx 、timerCtx 类型,且父context 没有关闭,则 将本cancel context 注册添加到父context 的children 列表中。cancelCtx 、timerCtx 类型 的context 在取消关闭时,会自动将children context 列表中的所有的子context 关闭;
- 如果不是系统 cancelCtx 、timerCtx 类型,起一个新的协程,监控 父context 的关闭状态;
func propagateCancel(parent Context, child canceler)
if parent.Done() == nil
return // parent is never canceled
if p, ok := parentCancelCtx(parent); ok
p.mu.Lock()
if p.err != nil
// parent has already been canceled
child.cancel(false, p.err)
else
if p.children == nil
p.children = make(map[canceler]struct)
//将自己加入到 父context 的子context 列表中;
p.children[child] = struct
p.mu.Unlock()
else
//如果不是 系统的cancelCtx 、timerCtx 类型,比如自定义的context 类型,系统不知道你何时关闭,也不知道你关闭时怎么处理,只能盲 监听状态;
go func()
select
case <-parent.Done():
child.cancel(false, parent.Err())
case <-child.Done():
()
3. 关闭 cancel context 的子context
cancelCtx 有一个内部数据结构,会保持该 context 下所有的子context,存放在children 接口体中。
type cancelCtx struct
Context
mu sync.Mutex // protects following fields
done chan struct // created lazily, closed by first cancel call
children map[canceler]struct // set to nil by the first cancel call
err error // set to non-nil by the first cancel call
当本context 取消时,会将children 中的所有的context进行取消。
func (c *cancelCtx) cancel(removeFromParent bool, err error)
if err == nil
panic("context: internal error: missing cancel error")
c.mu.Lock()
if c.err != nil
c.mu.Unlock()
return // already canceled
c.err = err
if c.done == nil
c.done = closedchan
else
close(c.done)
for child := range c.children
// NOTE: acquiring the child's lock while holding parent's lock.
child.cancel(false, err)
c.children = nil
c.mu.Unlock()
if removeFromParent
removeChild(c.Context, c)
以上是关于goland WithCancel分析的主要内容,如果未能解决你的问题,请参考以下文章