介绍
context用于多go协程中,控制go协程的结束,及传递值
对于存在父子关系的ctx,一旦cancel父ctx,所有子ctx一起cancel
type Context interface {
Deadline() (deadline time.Time, ok bool) //返回context预定结束的时间,如果没有设置结束时间,ok返回false
Done() <-chan struct{} //当context结束,返回一个channel。 可结合WithCancel、WithDeadline、WithTimeout使用
Err() error //Done被close之前返回nil,被close之后返回context结束的原因
Value(key interface{}) interface{} //和context.WithValue一起使用,可根据key返回value,对于没有在前文赋值的key返回nil
}
func Background() Context //返回一个初始化的context
type CancelFunc func() //立即cancel对应的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
func ExampleWithCancel() {
gen := func(ctx context.Context) <-chan int {
dst := make(chan int)
n := 1
go func() {
for {
select {
case <-ctx.Done():
return //context结束时,结束go协程
case dst <- n:
n++
}
}
}()
return dst
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel() //函数结束前同时canael所有context
for n := range gen(ctx) { //同一个ctx产生了5个下文
fmt.Println(n)
if n == 5 {
break
}
}
// Output:
// 1
// 2
// 3
// 4
// 5
}
func ExampleWithDeadline() {
d := time.Now().Add(50 * time.Millisecond)
ctx, cancel := context.WithDeadline(context.Background(), d)
defer cancel() //这一句是个好习惯。虽然超时context会被cancel,但context不用时立马cancel,可能更快释放资源
select {
case <-time.After(1 * time.Second):
fmt.Println("overslept")
case <-ctx.Done():
fmt.Println(ctx.Err())
}
// Output:
// context deadline exceeded
}
//与上一个类似
func ExampleWithTimeout() {
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
defer cancel()
select {
case <-time.After(1 * time.Second):
fmt.Println("overslept")
case <-ctx.Done():
fmt.Println(ctx.Err())
}
// Output:
// context deadline exceeded
}
func ExampleWithValue() {
//当一个ctx的父子关系较多且分布在不同包内时,给context传入的key最好使用自建类型,避免比较key时与预期不符。当然不复杂时用内置类型也可以
f := func(ctx context.Context, k interface{}) {
if v := ctx.Value(k); v != nil {
fmt.Println("found value:", v)
return
}
fmt.Println("key not found:", k)
}
ctx := context.WithValue(context.Background(), 1, "Go")
ctx = context.WithValue(ctx, "language2", "Python")
ctx = context.WithValue(ctx, 3, "Java")
f(ctx, 3)
f(ctx, "language4")
//output
//found value: Java
//key not found: language4
}
用于etcd处理超时
func main() {
config := clientv3.Config{
Endpoints:[]string{"127.0.0.1:2379"},
DialTimeout:10*time.Second,
}
client,err := clientv3.New(config)
if err != nil {panic(err)}
defer client.Close()
go func() {
n :=0
for {
n++
time.Sleep(time.Second * 1)
ctx,cancel := context.WithTimeout(context.Background(),time.Second)
_,err :=client.Put(ctx, "key", string(n))
cancel()
if err != nil{fmt.Println(err)}
}
}()
for{
watch := client.Watch(context.Background(),"key")
for watchResponse := range watch{
for _,ev := range watchResponse.Events{
fmt.Println(ev.Type,string(ev.Kv.Key),ev.Kv.Value[0])
}
}
}
}