1. 内部结构之 - timerCtx 。
type timerCtx struct { cancelCtx timer *time.Timer // Under cancelCtx.mu. deadline time.Time }
- 里面有一个 timer,用来触发超时之后的 回调函数,也就是超时之后,帮你 cancel 一下。理论上,你不用在结构体里存一份这个,这里存了这个指针,主要是用来取消这个定时触发,基本上就是因为一个定时器你如果不需要了,就要马上回收这个资源,否则会很耗资源的。例如,假设,你有一个十分钟的超时触发机制,不过由于某些原因,这个context被其他东西cancel了,那么这十分钟内,内部的定时器还要继续工作,这难道不是很浪费么,就像你们几个人玩游戏,让一个人记录分数,这时你们上司来了,这个游戏完不成了,难道那个记录分数的同事还傻乎乎的继续记么,,,,很明显太二了,所以要及时的终止这个计时器。
- 这个deadline就是那个预设的超时的绝对时间。同时,实现了Context的 Deadline接口。
- 关键就是里面的 cancelCtx,首先这是一个结构体,不是接口,也不是指针。可以从这个源码里来思考思考,什么时候在struct里面直接用struct,什么时候在里面埋一个interface,什么时候在里面用一个 *struct。把timeCtx分开成两个单词,一个是time,一个是Context,那么上面两个字段承载了有关【time】的东西,那么可以猜到,这个cancelCtx就承载了【Context】的功能。所以来看看这个cancelCtx是个什么鬼?
1.1 cacelCtx 的结构分析。
type cancelCtx struct { Context done chan struct{} // closed by the first cancel call. mu sync.Mutex children map[canceler]bool // set to nil by the first cancel call err error // set to non-nil by the first cancel call }
- 先来插一句,代码如何抽象,当然是见仁见智,但是这里把cancelCtx放在 timeCtx里面,而且是以 struct的形式,没有用指针,也没有用interface,我认为,,我认为是因为,这个cancelCtx是属于timeCtx的一部分,正是这一部分体现了,timeCtx 确实是一个Context。
- done字段:作为一个Context,必须要有 Done()方法,这个方法要返回一个 chan struct{}, 那么很明显,这个字段就是来干这个的。
- err字段: 同上,作为一个Context,必须要有 Err()方法,,,返回一个错误,很明显,这个字段就是用来干这个的。
- mu字段: 用来保证并发操作的。
- children字段:golang 的 context 包用一种 【父-子】的关系来管理【一个业务需求】引发的【各个子goroutine】所关联的各个【Context】,很明显,这个children字段用来记录,谁是我的儿子。
- Context字段:这是一个接口,用来存放【父Context】。注意到,要想成为 Context必须实现四个方法。最后一个方法就是Value() 。我们发现,现在为止只有三个被实现了,那就是Deadline,Done,Err。那么谁来实现Value呢。。。就是这个埋进来的Context了。也就是说,你作为一个timeCtx,你仅仅有【时间】的概念,你不应该有【Value】的概念,【Value】的概念,你从你的【父Context】那里直接伸手去要,恩,大概就这个意思。{插:这个Context包还讲解了golang的面向对象风格是啥么样的形态,所以说看源码涨知识啊。。}。