go标准库Context

介绍

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])
			}
		}
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值