源码中我们可以得知有 context 是一个 interface,
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key any) any
}
func Background() Context
func TODO() Context
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{}) Context
Deadline 方法需要返回当前 Context 被取消的时间,也就是完成工作的截止时间(deadline);
Done 方法需要返回一个 Channel
,这个 Channel 会在当前工作完成或者上下文被取消之后关闭,多次调用 Done 方法会返回同一个 Channel;
Value 方法会从 Context 中返回键对应的值,对于同一个上下文来说,多次调用 Value 并传入相同的 Key 会返回相同的结果,该方法可用于传递跨 API 和进程间跟请求域的数据;
// Background returns a non-nil, empty Context. It is never canceled, has no
// values, and has no deadline. It is typically used by the main function,
// initialization, and tests, and as the top-level Context for incoming
// requests.
func Background() Context {
return background
}
示例代码
func main() {
ctx := context.Background()
sleepAndTalk(ctx, 5*time.Second, "hello")
}
func sleepAndTalk(ctx context.Context, d time.Duration, msg string) {
select {
case <-ctx.Done():
fmt.Println("done")
case <-time.After(d):
fmt.Println(msg)
}
}
Background()常用于初始化以及测试代码,作为 top-level 的 context。
TODO(),没有什么具体含义,但是又必须传递 ctx 的时候可以使用。
二者的共同点都是,没有 deadling, 没有 value, 没有 cancle
的 empty context
func main() {
ctx := context.Background()
ctx, cancle := context.WithCancel(ctx)
// 1. 用户输入信息后context 执行cancle, 2022-11-21-22:54 控制台输出context deadline exceeded
// go func() {
// s := bufio.NewScanner(os.Stdin)
// s.Scan()
// cancle()
// }()
// 2. 1s之后取消,然后控制台输出 context deadline exceeded
// go func() {
// time.Sleep(time.Second)
// cancle()
// }()
// 3. 或者可以使用time.afterfunc 同2方法一样效果
time.AfterFunc(time.Second, cancle)
sleepAndTalk(ctx, 5*time.Second, "hello")
}
func sleepAndTalk(ctx context.Context, d time.Duration, msg string) {
select {
case <-ctx.Done():
fmt.Println(ctx.Err())
case <-time.After(d):
fmt.Println(msg)
}
}
func main() {
ctx := context.Background()
ctx, cancle := context.WithTimeout(ctx, time.Second)
defer cancle()
sleepAndTalk(ctx, 5*time.Second, "hello")
}
func sleepAndTalk(ctx context.Context, d time.Duration, msg string) {
select {
case <-ctx.Done():
fmt.Println(time.Now().Format("2006-01-02-15:04"), "context cancled")
case <-time.After(d):
fmt.Println(msg)
}
}
std: 2022-11-21-22:59 context cancled
func Decorate(f http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
// 随机 63 位整数作为 int64。
id := rand.Int63()
ctx = context.WithValue(ctx, reqIdkey, id)
r = r.WithContext(ctx)
f(w, r)
}
}
整个代码参考以 http server、client、log
server
client
http_log