Golang context 源码阅读

12 篇文章 0 订阅
10 篇文章 0 订阅

一、Context功能

  • 控制goroutine超时退出
  • 在goroutine传递一些变量

二、Context包的主要结构

  1. Context接口

        type Context interface {
        	// 调用此方法返回该context超时应该取消的时间点,如果ok=true,说明设置了超时取消的时间为deadline,如果ok=false则未设置。
        	Deadline() (deadline time.Time, ok bool)
        	// Done方法返回一个关闭的channel当工作完成后,如果工作为完成应该返回nil(golang官方有篇文章([https://blog.golang.org/pipelines](https://blog.golang.org/pipelines))描写怎样用channel来作为取消功能)。
        	Done() <-chan struct{}
        	// 如果Done还没有被关闭返回nil,如果关闭了则返回一个非空的错误来解释取消原因。
        	Err() error
        	// 存储在context的键值对
        	Value(key interface{}) interface{}
        }
    
  2. Context接口实现
    2.1. emptyCtx

    // emptyCtx 不能被取消,不能存储值,不能设置超时
    type emptyCtx int
    
    // 以下是emptyCtx实现Context接口的具体代码,没有任何的逻辑,都是空。
    
    func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
    	return
    }
    
    func (*emptyCtx) Done() <-chan struct{} {
    	return nil
    }
    
    func (*emptyCtx) Err() error {
    	return nil
    }
    
    func (*emptyCtx) Value(key interface{}) interface{} {
    	return nil
    }
    
    // background, todo都是emptyCtx的实例,backgroud一般用于整个程序初始化的时候的context,todo一般用于不知道用哪个context时使用它。
    var (
    	background = new(emptyCtx)
    	todo       = new(emptyCtx)
    )
    

    2.2 cancelCtx

    // cancelCtx实现了Context,也实现了canceler,它可以被取消,同时也把子context也取消。
    type cancelCtx struct {
    	Context
    
    	mu       sync.Mutex            // 当并发时控制以下字段
    	done     chan struct{}         // 懒惰创建,在第一次调用cancel时会关闭
    	children map[canceler]struct{} // 在第一次调用cancel时会设置为nil
    	err      error                 // 在第一次调用cancel时会被设置成非空
    }
    // canceler接口
    type canceler interface {
    	cancel(removeFromParent bool, err error)
    	Done() <-chan struct{}
    }
    
    // cancelCtx实现canceler接口的Done方法
    func (c *cancelCtx) Done() <-chan struct{} {
    	c.mu.Lock()
    	if c.done == nil {
    		c.done = make(chan struct{})
    	}
    	d := c.done
    	c.mu.Unlock()
    	return d
    }
    
    // cancelCtx实现canceler接口的cancel方法
    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)
    	}
    }
    
    // cancelCtx实现过程在WithCancel函数
    // 1.WithCancel函数返回一个cancelCtx和cancelFunc
    func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
    	c := newCancelCtx(parent)
    	propagateCancel(parent, &c)
    	return &c, func() { c.cancel(true, Canceled) }
    }
    // 2.WithCancel函数内部会将cancelCtx注册到父的context中(如果父context是可取消的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{})
    			}
    			p.children[child] = struct{}{}
    		}
    		p.mu.Unlock()
    	} else {
    		// 这里表示只会取消cancelCtx类型的context
    		go func() {
    			select {
    			case <-parent.Done():
    				child.cancel(false, parent.Err())
    			case <-child.Done():
    			}
    		}()
    	}
    }
    

    2.3 timerCtx

    // timerCtx接口嵌入(继承)cancelCtx
    type timerCtx struct {
    	cancelCtx
    	timer *time.Timer // Under cancelCtx.mu.
    
    	deadline time.Time
    }
    

    2.4 valueCtx

    // valueCtx携带key-value,嵌入Context接口
    type valueCtx struct {
    	Context
    	key, val interface{}
    }
    
  3. 重要的包级函数
    3.1 WithCancel(parent Context) (ctx Context, cancel CancelFunc):返回context和取消函数。
    3.2 WithDeadline(parent Context, d time.Time) (Context, CancelFunc):返回context和取消函数,并且设置超时自动取消的时间。
    3.3 WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) :和WithDeadline相似,但是时间参数换成了相对时间。
    3.4 WithValue(parent Context, key, val interface{}) Context:传入key-value,返回context

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值