Context的使用场景
Context的设计初衷就是为了在多个goroutine之间传递和同步取消信号,以减少资源的消耗和占用,具体有以下使用场景:
- 作为请求API的调用方&被调用方时的超时控制,通常用于数据库或者网络连接的超时控制;
- 作为各协程之间共用的变量池例如Gin框架中各中间件链式调用时互相传递Context;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17type Context interface {
// Deadline returns the time when work done on behalf of this context
// should be canceled.
Deadline() (deadline time.Time, ok bool)
// Done returns a channel that's closed when work done on behalf of this
// context should be canceled.
Done() <-chan struct{}
// If Done is not yet closed, Err returns nil.
// If Done is closed, Err returns a non-nil error explaining why:
// Canceled if the context was canceled
// or DeadlineExceeded if the context's deadline passed.
Err() error
// Value returns the value associated with this context for key, or nil
// if no value is associated with key. Successive calls to Value with
// the same key returns the same result.
Value(key any) any
}
Context超时控制的实现原理
通过Done()
传递超时信号,并使用Select监听超时信号是否传入,官方注释如下
1 | // Done is provided for use in select statements: |
Context的Keys池如何保证线程安全
官方context
包下的Context接口内部对Keys没有使用传统锁的机制来保证线程安全,每次对Context
的操作都会创建一个新的上下文实例,而不是改变现有的实例(通过WithDeadline()
,WithTimeOut()
和WithCancle()
这些方法派生父节点上下文的副本),这样的设计避免了对共享资源的直接修改,从而避免了锁的需要。
1 | func WithValue(parent Context, key, val any) Context { |
Gin框架实现的Context
内部是通过读写锁保证Key-Value变量池的线程安全
1 | // Set is used to store a new key/value pair exclusively for this context. |