t 包, 用于 golang 函数链安全的管理和控制.
说真 golang context 实现非常漂亮, 代码中说明也事无巨细, 整体很赏心悦目.
那我们带大家宏观过一遍 context 设计布局.
// Context 上下文调用链条
type Context interface {
// Deadline 返回是否完成和结束时刻
Deadline() (deadline time.Time, ok bool)
// Done 返回是否完成的阻塞 chan
Done() (done <-chan struct{})
// Err Done 时候储存 error 信息, Canceled or DeadlineExceeded
Err() (err error)
// Value Context 中获取 key 的值
Value(key interface{}) (val interface{})
}
// emptyCtx 永远不会被取消的 context
type emptyCtx int
// cancelCtx 可被取消的 context
type cancelCtx struct { Context ... }
// timerCtx 带计时器和截止日期的 cancelCtx
type timerCtx struct { cancelCtx ... }
// valueCtx 储存键值对 context
type valueCtx struct {
Context
key, val interface{}
}
可以看出 Context 是个 interface, context.go 中有四种结构实现了 Context interface, 分别
是 emptyCtx, cancelCtx, timerCtx, valueCtx. 细看这类数据结构设计思路, 只记录父亲是谁,
单线联系. 可以反着类比普通树结构只记录儿子是谁哈哈, 大众货居然被玩出?, 真强.
正文 - context 手写
废话不多说, 开始写代码. 上面 context.go 文件一把梭哈, 对于初学者还是无从学起的. 我们
这里按照结构分模式展开书写,
├── context
│ ├── cancel.go
│ ├── context.go
│ ├── empty.go
│ ├── timer.go
│ ├── value.go
│ └── with.go
让其看起来好理解些.
context.go
package context
import (
"errors"
"time"
)
// Canceled 取消上下文时 context.Err 返回的错误
var Canceled = errors.New("context canceled")
// DeadlineExceeded 上下文超时时候 Context.Err 返回的错误
var DeadlineExceeded error = deadlineExceededError{}
type deadlineExceededError struct{}
func (deadlineExceededError) Error() string { return "context deadline exceeded" }
func (deadlineExceededError) Timeout() bool { return true }
func (deadlineExceededError) Temporary() bool { return true }
// Context 上下文调用链条
type Context interface {
// Deadline 返回是否完成和结束时刻
Deadline() (deadline time.Time, ok bool)
// Done 返回是否完成的阻塞 chan
Done() (done <-chan struct{})
// Err Done 时候储存 error 信息, Canceled or DeadlineExceeded
Err() (err error)
// Value Context 中获取 key 的值
Value(key interface{}) (val interface{})
}
empty.go
package context
import "time"
// emptyCtx 永远不会被取消的 context
type emptyCtx int
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) { return }
func (*emptyCtx) Done() (done <-chan struct{}) { return }
func (*emptyCtx) Err() (err error) { return }
func (*emptyCtx) Value(key interface{}) (val interface{}) { return }
var (
background = new(emptyCtx)
todo = new(emptyCtx)
)
// String emptyCtx 打印方法
func (e *emptyCtx) String() string {
switch e {
case background:
return "context.Background"
case todo:
return "context.TODO"
}
return "unknown empty Context"
}
// Background 不会被取消的 context, 一般用做顶级 context
func Background() Context {
return background
}
// TODO 当你不知道用什么 Context 时候, 记住那就用这个
func TODO() Context {
return todo
}
cancel.go
package context
import (
"reflect"
"sync"
)
type stringer interface {
String() string
}
func contextName(c Context) string {
if s, ok := c.(stringer); ok {
return s.String()
}
return reflect.TypeOf(c).String()
}
// canceler 可以直接取消的上下文, 详情见 *cancelCtx 和 *timerCtx
type canceler interface {
cancel(removeFromParent bool, err error)
Done() (done <-