type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key interface{}) interface{}
}
Context接口包含四个方法:
- Deadline返回绑定当前context的任务被取消的截止时间;如果没有设定期限,将返回ok == false。
- Done 当绑定当前context的任务被取消时,将返回一个关闭的channel;如果当前context不会被取消,将返回nil。
- Err 如果Done返回的channel没有关闭,将返回nil;如果Done返回的channel已经关闭,将返回非空的值表示任务结束的原因。如果是context被取消,Err将返回Canceled;如果是context超时,Err将返回DeadlineExceeded。
- Value 返回context存储的键值对中当前key对应的值,如果没有对应的key,则返回nil。
父节点Context可以主动通过调用cancel方法取消子节点Context,而子节点Context只能被动等待。同时父节点Context自身一旦被取消(如其上级节点Cancel),其下的所有子节点Context均会自动被取消。
有三种创建方法:
// 带cancel返回值的Context,一旦cancel被调用,即取消该创建的context
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
// 带有效期cancel返回值的Context,即必须到达指定时间点调用的cancel方法才会被执行
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
// 带超时时间cancel返回值的Context,类似Deadline,前者是时间点,后者为时间间隔
// 相当于WithDeadline(parent, time.Now().Add(timeout)).
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
package main
import (
"context"
"fmt"
"log"
"os"
"time"
)
var logg *log.Logger
func someHandler() {
//ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
go doStuff(ctx) //这个协程有5s的超时时间限制
//10秒后取消doStuff
time.Sleep(30 * time.Second)
logg.Printf("wait")
cancel() // cancel被调用,即取消该创建的ctx
}
//每1秒work一下,同时会判断ctx是否被取消了,如果是就退出
func doStuff(ctx context.Context) {
for {
time.Sleep(1 * time.Second)
select {
case <-ctx.Done():
logg.Printf("done")
return
default:
logg.Printf("work")
}
}
}
func main() {
logg = log.New(os.Stdout, "", log.Ltime)
someHandler()
logg.Printf("down")
}
以上执行结果:可以看出doStuff在5s之后执行结束(超时时间限制),context的cancel是在30s之后