goland WithCancel分析

Posted 安然_随心

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了goland WithCancel分析相关的知识,希望对你有一定的参考价值。

文章目录


WithCancel 返回context ,该context 是父context 的一个完整的拷贝,该新的context 有自己新的Done Channel。

WithCancel 有两个核心的功能:

  1. 当父context 关闭的时候,需要将本cancel context 关闭;
  2. 调用 cancel context 返回的cancel func 的时候,需要将本cancel context 和 cancel context 的子 context 取消关闭。

从下面三个部分来说明:

  1. context 接口;
  2. 怎么做到父context 关闭, 新的cancel context 关闭;
  3. 如何关闭 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 中实现此功能,实现的方式如下:

  1. 在新建 cancel context 时,如果 父context 的done 通道关闭,则父context 无法被取消了;
  2. 如果父 context 是系统 cancelCtx 、timerCtx 类型,且父 context 已经关闭了,则现在就可以直接关闭 新的cancel context 了;
  3. 如果父 context 是系统 cancelCtx 、timerCtx 类型,且父context 没有关闭,则 将本cancel context 注册添加到父context 的children 列表中。cancelCtx 、timerCtx 类型 的context 在取消关闭时,会自动将children context 列表中的所有的子context 关闭;
  4. 如果不是系统 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分析的主要内容,如果未能解决你的问题,请参考以下文章

go context包的WithTimeout和WithCancel的使用

goland新建的文件默认是lf

goland2019激活方法

IDEA/GoLand 添加自定义特殊注释注释高亮

IDEA/GoLand 添加自定义特殊注释注释高亮

goland没有自动补全功能的问题解决