最近听了一位同事的分享,他说如果一个人不能把它所研究的项目/概念用十分简单的话表述清楚,那么就说明他并没有真正理解这个项目。然后他拿物理中粒子的自旋进行举例,有人向教授请教相关概念,教授说:我需要思考一下如何用浅显的话进行表述。稍许之后,教授说:很抱歉,可能我只能用非常复杂的公式和概念向你解释了。这说明了可能人类对于这一现象的本质并没有理解。
结合我的上一篇文章 最近的一些感悟 - 体系的力量 ,这更加说明了我们在学习的时候其实就是拨开繁杂的迷雾,去窥探一个概念、一个项目、一个体系它最核心的本质。计算机是一门科学,由人类创造,所以我们应该是能力用简单的话将它表述清楚的。所以我也会以这样的要求来进行写作,力求用最简单、清晰的语言来描述。
今天的内容是golang中的context包中的Context接口。
基本概念
context.Context本身为interface(接口),主要用于父协程关闭后可以同步关闭所有子孙协程,是一种并发控制/协程同步的重要手段。
那么我们实现Context,只需要实现Done, Err, Value, Deadline四个方法即可:
- Done方法返回一个channel,在子协程中配合select … case使用,用于监听父协程关闭的事件:
需要取消context时close该channel,则case处会继续向下走;
select {
case <- ctx.Done():
// xxxx ctx关闭后的一些操作
} - Err返回context被取消的原因如context canceled(主动关闭), context deadline exceeded(超时关闭)
- Value返回context中保存的上下文数据,kv形式
- Deadline返回context的超时时间
几种Context的具体实现
context包中提供了如withCancel, withTimeout等一系列方法用于创建子context。context之间呈树状结构,当传递事件(如取消)/数据时,可以递归地从上到下进行传递以控制子孙协程。
一些重点方法的说明
WithCancel:
- 创建新的cancelCtx, 放入父context(匿名结构体)
- 如果父context为cancelCtx,将自身加入父context的children中
- 如果父context不是cancelCtx,则持续向上寻找直到找到cancelCtx类型
- 如果找到根节点仍未找到cancelCtx类型,则监听父context.Done() 用于当父协程退出时候取消自身
Cancel:
- 关闭自身的done channel并给err赋值为context canceled
- 遍历children,调用它们的cancel方法(递归地关闭所有子孙协程)
- 将自身从父context的children中移出
WithDeadline:
- 初始化一个cancelCtx,复用它的 cancel,done等方法
- 启动一个定时器,使用time.AfterFunc( dur, func ) 在一段时间后调用自身的cancel方法
WithTimeout:实际上也是调用WithDeadline
有疑问加站长微信联系(非本文作者)