马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
Context上下文
Context概述
Go 1.7 标准库引入 context,译作“上下文”,精确说它是 goroutine 的上下文,包罗 goroutine 的运行状态、环境、现场等信息。
context 重要用来在 goroutine 之间通报上下文信息,包罗:取消信号、超时时间、制止时间、k-v 等。
随着 context 包的引入,标准库中许多接口因此加上了 context 参数,比方 database/sql 包。context 险些成为了并发控制和超时控制的标准做法。
在一组goroutine 之间通报共享的值、取消信号、deadline是Context的作用。
以典范的HTTPServer为例:
我们以 Context II为例,若没有上下文信号,当此中一个goroutine出现标题时,其他的goroutine不知道,还会继承工作。如许的无效的goroutine积攒起来,就会导致goroutine雪崩,进而导致服务宕机!
没有同步信号:
增长同步信号:
参考:Context通报取消信号 小结。
Context 核心结构
context.Context 是 Go 语言在 1.7 版本中引入标准库的接口,该接口界说了四个必要实现的方法:
- type Context interface {
- // 返回被取消的时间
- Deadline() (deadline time.Time, ok bool)
- // 返回用于通知Context完结的channel
- // 当这个 channel 被关闭时,说明 context 被取消了
- // 在子协程里读这个 channel,除非被关闭,否则读不出来任何东西
- Done() <-chan struct{}
- // 返回Context取消的错误
- Err() error
- // 返回key对应的value
- Value(key any) any
- }
复制代码 除了Context接口,还存在一个canceler接口,用于实现Context可以被取消:
- type canceler interface {
- cancel(removeFromParent bool, err error)
- Done() <-chan struct{}
- }
复制代码 除了以上两个接口,另有4个预界说的Context范例:
- // 空Context
- type emptyCtx int
-
- // 取消Context
- type cancelCtx struct {
- Context
- mu sync.Mutex // protects following fields
- done atomic.Value // of chan struct{}, created lazily, closed by first cancel call
- children map[canceler]struct{} // set to nil by the first cancel call
- err error // set to non-nil by the first cancel call
- }
-
- // 定时取消Context
- type timerCtx struct {
- cancelCtx
- timer *time.Timer // Under cancelCtx.mu.
-
- deadline time.Time
- }
-
- // KV值Context
- type valueCtx struct {
- Context
- key, val any
- }
-
复制代码 默认(空)Context的使用
context 包中最常用的方法是 context.Background、context.TODO,这两个方法都会返回预先初始化好的私有变量 background 和 todo,它们会在同一个 Go 步伐中被复用:
- context.Background, 是上下文的默认值,全部其他的上下文都应该从它衍生出来,在多数环境下,假如当前函数没有上下文作为入参,我们都会使用 context.Background 作为起始的上下文向下通报。
- context.TODO,是一个备用,一个context占位,通常用在并不知道通报什么 context的环境。
使用示例,database/sql包中的实验:
- func (db *DB) PingContext(ctx context.Context) error
- func (db *DB) ExecContext(ctx context.Context, query string, args ...any) (Result, error)
- func (db *DB) QueryContext(ctx context.Context, query string, args ...any) (*Rows, error)
- func (db *DB) QueryRowContext(ctx context.Context, query string, args ...any) *Row
复制代码 方法,此中第一个参数就是context.Context。
比方:使用时:
- db, _ := sql.Open("", "")
- query := "DELETE FROM `table_name` WHERE `id` = ?"
- db.ExecContext(context.Background(), query, 42)
复制代码 固然,单独 database.sql包中,也支持不通报context.Context的方法。功能同等,但缺失了context.Context干系功能。
- func (db *DB) Exec(query string, args ...any) (Result, error)
复制代码 context.Background 和 context.TODO 返回的都是预界说好的 emptyCtx 范例数据,其结构如下:
- // 创建方法
- func Background() Context {
- return background
- }
- func TODO() Co
复制代码 |