GO 语言中 Context 包详解
Rreality is merely an illusion, albeit a very persistent one.
前言
contextcontext.TODO()Context
Context
GVAContext
Context
埋头苦学往往只是知其形而不知其意,只有实际做项目才能够真正的掌握一门语言
一、Context 介绍
1.1 Context 是什么?
ContextGo1.7GoGoroutineGoroutine
GogoroutinegoroutinegoroutineRPCgoroutinetokengoroutineGooglecontextgoroutine
Contextgoroutinegoroutinechannelgoroutinedone channel
ContextContextContext
Context 使用场景
- 上下文信息传递 (request-scoped),比如处理 http 请求、在请求处理链路上传递信息
- 控制子 goroutine 的运行
- 超时控制的方法调用
- 可以取消的方法调用
1.2 Context 接口
contextContext
// A Context carries a deadline, cancellation signal, and request-scoped values
// across API boundaries. Its methods are safe for simultaneous use by multiple
// goroutines.
type Context interface {
// Done returns a channel that is closed when this Context is canceled
// or times out.
Done() <-chan struct{}
// Err indicates why this context was canceled, after the Done channel
// is closed.
Err() error
// Deadline returns the time when this Context will be canceled, if any.
Deadline() (deadline time.Time, ok bool)
// Value returns the value associated with key or nil if none.
Value(key interface{}) interface{}
}
DonechannelcontextchannelDoneErrerrorcontextDone channelDeadlinedeadlineValuecontextgoroutine
DonecloseErrnilDonecloseErrDoneclose
二、Context 的使用
GoogleContextGoContextgoroutine
contextContext
- context.Background()
- context.TODO()
这两个函数互为别名,没有差别,官方定义:
context.Backgroundcontext.TODO()
contextcontextwith
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
ContextContext
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SslcluBn-1656939722939)(./images/context-derive.png)]
2.1 WithValue 携带数据、Value 获取数据
GVAcontext
// InitDB 创建数据库并初始化 总入口
func (initDBService *InitDBService) InitDB(conf request.InitDB) (err error) {
ctx := context.TODO()
var initHandler TypedDBInitHandler
initHandler = NewMysqlInitHandler()
ctx = context.WithValue(ctx, "dbtype", "mysql")
ctx, _ = initHandler.EnsureDB(ctx, &conf)
db := ctx.Value("db").(*gorm.DB)
global.GVA_DB = db
if err = initHandler.WriteConfig(ctx); err != nil {
return err
}
if err = initHandler.InitTables(ctx, initializers); err != nil {
return err
}
if err = initHandler.InitData(ctx, initializers); err != nil {
return err
}
return nil
}
// EnsureDB 创建数据库并初始化 mysql
func (h MysqlInitHandler) EnsureDB(ctx context.Context, conf *request.InitDB) (next context.Context, err error) {
if s, ok := ctx.Value("dbtype").(string); !ok || s != "mysql" {
return ctx, ErrDBTypeMismatch
}
c := conf.ToMysqlConfig()
next = context.WithValue(ctx, "config", c)
next = context.WithValue(next, "db", db)
}
// WriteConfig mysql回写配置
func (h MysqlInitHandler) WriteConfig(ctx context.Context) error {
c, _ := ctx.Value("config").(config.Mysql)
global.GVA_CONFIG.Mysql = c
return global.GVA_VP.WriteConfig()
}
context.TODO()ctxcontext.WithValuedbtypeconfigdbcontextcontextcontext
context
InitDBdbtypeEnsureDBValuedbtypeEnsureDBconfigdbWriteConfigconfigInitDBdbgorm.DB
withValue
contextvaluekeyvaluecontextcontextkeycontextcontextcontextnilcontextkeyvalueinterface
2.2 WithCancel 取消控制
goroutinegoroutinewithCancelcontextgoroutinegoroutinecancel
InitTablesInitData
func (h MysqlInitHandler) InitTables(ctx context.Context, inits initSlice) error {
return createTables(ctx, inits)
}
// createTables 创建表(默认 dbInitHandler.initTables 行为)
func createTables(ctx context.Context, inits initSlice) error {
next, cancel := context.WithCancel(ctx)
defer func(c func()) { c() }(cancel)
return nil
}
func (h MysqlInitHandler) InitData(ctx context.Context, inits initSlice) error {
next, cancel := context.WithCancel(ctx)
defer func(c func()) { c() }(cancel)
return nil
}
GVAgoroutinecontext
contextgoroutine
func main() {
ctx,cancel := context.WithCancel(context.Background())
go CancelText(ctx)
time.Sleep(10*time.Second)
cancel()
time.Sleep(1*time.Second)
}
func CancelText(ctx context.Context) {
for range time.Tick(time.Second){
select {
case <- ctx.Done():
fmt.Println("stop time")
return
default:
fmt.Println("start time")
}
}
}
WithCancelBackgroundctxmainCancelTextstart time
主协程在 10s 后执行 cancel,CancelText 子协程检测到取消信号后退出