源码分析context的超时及关闭实现

栏目: 编程工具 · 发布时间: 5年前

内容简介:前言:下面的结构图就很形象的说明了各个context 的关联关系。context节点通过children map来连接 子context节点。总之,context节点是层层关联的。

前言:

Golang的 context的作用就不多说了,就是用来管理调用上下文的,控制一个请求的生命周期。golang的context库里有四个组件。 withCancel用来控制取消事件,withDeadline和withTimeout是控制超时,withValue可以传递一些key value。 

// xiaorui.cc
 
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
 
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
 
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
 
func WithValue(parent Context, key, val interface{}) Context

下面的结构图就很形象的说明了各个context 的关联关系。context节点通过children map来连接 子context节点。总之,context节点是层层关联的。

该文章后续仍在不断的更新修改中, 请移步到原文地址     http://xiaorui.cc/?p=5604

源码分析context的超时及关闭实现

上面的功能介绍倒是没什么,让我好奇的是go context是怎么实现的超时和链式关闭。究其原理,还是要分析context的源代码, WithTimeout也是通过WithDeadline来实现的。

func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
	return WithDeadline(parent, time.Now().Add(timeout))
}

通过下面的WithDeadline方法,我们可以分析出 创建一个子context及定时器过程,

// xiaorui.cc
 
type timerCtx struct {
	cancelCtx
	timer *time.Timer // Under cancelCtx.mu.
 
	deadline time.Time
}
 
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) {
        ...
	c := &timerCtx{
		cancelCtx: newCancelCtx(parent),   // 返回一个子的context
		deadline:  d,
	}
        //  添加父节点和子节点的关联关系
	propagateCancel(parent, c)
	dur := time.Until(d)
	if dur <= 0 {
		c.cancel(true, DeadlineExceeded) // deadline has already passed
		return c, func() { c.cancel(true, Canceled) }
	}
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.err == nil {
                //  添加定时器
		c.timer = time.AfterFunc(dur, func() {
			c.cancel(true, DeadlineExceeded)
		})
	}
        // 返回 context 和 关闭的方法
	return c, func() { c.cancel(true, Canceled) }
}
 
// newCancelCtx returns an initialized cancelCtx.
func newCancelCtx(parent Context) cancelCtx {
	return cancelCtx{Context: parent}
}

context是怎么链式关闭的? 先前分析源码的时候整错了,以为会new一个协程来监听父节点的context的存活。

// xiaorui.cc
 
func propagateCancel(parent Context, child canceler) {
    ...
	} else {
		go func() {
			select {
			case <-parent.Done():
				child.cancel(false, parent.Err())
			case <-child.Done():
			}
		}()
	}
}

但想来golang在1.9后内置了context作为标准库, 它不能这么粗暴,现在golang社区里开源库都离不开context方法。为了关闭子节点context,new一个goroutine来监听父节点,这个太不合理。。。想来一定是没有仔细分析代码。。。果然。。。看错了。

// xiaorui.cc
 
func (c *timerCtx) cancel(removeFromParent bool, err error) {
        ...
	if removeFromParent {
		// Remove this timerCtx from its parent cancelCtx's children.
		removeChild(c.cancelCtx.Context, c)
	}
	c.mu.Lock()
	if c.timer != nil {
                // 关闭定时器
		c.timer.Stop()
		c.timer = nil
	}
	c.mu.Unlock()
}
 
// removeChild removes a context from its parent.
func removeChild(parent Context, child canceler) {
	p, ok := parentCancelCtx(parent)
	if !ok {
		return
	}
	p.mu.Lock()
	if p.children != nil {
		delete(p.children, child)  // 从父层里删除子节点
	}
	p.mu.Unlock()
}
 
func (c *cancelCtx) cancel(removeFromParent bool, err error) {
         ...
	c.mu.Lock()
        ...
	if c.done == nil {
		c.done = closedchan
	} else {
		close(c.done) // 关闭
	}
        // 层层关闭 ...
	for child := range c.children {
		child.cancel(false, err)
	}
	c.children = nil
	c.mu.Unlock()
 
        // 从父context child里删除子context节点
	if removeFromParent {
		removeChild(c.Context, c)
	}
}

总结:

context的源码很简单,代码也精简的,有兴趣的朋友可以细细的琢磨下。

end.

对Golang感兴趣的朋友可以加群: 278517979 !!!

另外如果大家觉得文章对你有些作用! 如果想 赏钱 ,可以用微信扫描下面的二维码, 感谢!

另外再次标注博客原地址   xiaorui.cc

源码分析context的超时及关闭实现 源码分析context的超时及关闭实现

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

因计算机而强大

因计算机而强大

[美]西摩 佩珀特 Seymour Papert / 梁栋 / 新星出版社 / 2019-1 / 38

本书有两个中心主题—— 孩子可以轻松自如地学习使用计算机; 学习使用计算机能够改变他们学习其他知识的方式。 (前苹果公司总裁 约翰·斯卡利) 最有可能带来文化变革的就是计算机的不断普及。 计算机不仅是一个工具,它对我们的心智有着根本和深远的影响。 计算机不仅帮助我们学习 ,还帮助我们学习怎样学习。 计算机是一种调解人与人之间关系的移情对象。 一个数学的头脑......一起来看看 《因计算机而强大》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

html转js在线工具
html转js在线工具

html转js在线工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换