Golang中Context学习

一、应用

       Go服务器的每个请求都有自己的goroutine,而有的请求为了提高性能,会经常启动额外的goroutine处理请求,当该请求被取消或超时,该请求上的所有goroutines应该退出,防止资源泄露。

 

二、使用

    1.Context接口

type Context interface {
 
   //Dealine()函数返回上下文应该取消的时间,如果没有设置超时时间则ok为false
   Deadline() (deadline time.Time, ok bool)

     //Done()返回一个close的channel用于关闭该上下文,如果该上下文不能关闭则返回nil
   //当cancel函数被调用时会使用Done去关闭,
   //当deadline到期后会使用Done去关闭
   Done() <-chan struct{}

   //如果Done未关闭,则Err返回nil
   //如果Done已关闭,则返回非空的error解释原因
   Err() error

     //Value通过key获取该key在上下文中关联的值,如果该key没有关联的值,则返回nil
   //多次调用同一个key,返回的结果是一样的
   Value(key interface{}) interface{}
}

 2.Context常用初始化创建方法

   1).func WithCancel(parent Context) (ctx Context, cancel CancelFunc)

   2). func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)

   3) .func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)

  注:WithTimeout 等同于 WithDeadline(parent, time.Now().Add(timeout)).

 

扫描二维码关注公众号,回复: 3228824 查看本文章

三、示例:

  1.常用方法示例

/*
context.WithCancel()
*/
func withCancel() {
	ctx,cancel := context.WithCancel(context.Background())
	go doStuff(ctx)
	//过7s取消该context
	time.Sleep(time.Second*7)
	cancel()
	time.Sleep(time.Second*2)
}

/*
context.WithTimeout()
*/
func withTimeout() {
	ctx,cancel := context.WithTimeout(context.Background(),time.Second*7)
	go doStuff(ctx)

	//退出ctx时间:在timeout和调用cancel时间点的最小值
	time.Sleep(time.Second*5)
	//time.Sleep(time.Second*10)
	cancel()
	time.Sleep(time.Second*2)
}

/*
context.WithDeadline()
WithTimeout 等价于 WithDeadline(parent, time.Now().Add(timeout))
*/
func withDeadline() {
	ctx,cancel := context.WithDeadline(context.Background(),time.Now().Add(time.Second*7))

	go doStuff(ctx)

	//退出ctx时间:在timeout和调用cancel时间点的最小值
	time.Sleep(time.Second*5)
	//time.Sleep(time.Second*10)
	cancel()
	time.Sleep(time.Second*2)
}

func doStuff(ctx context.Context) {
	for {
		time.Sleep(time.Second)
		select {
		case <-ctx.Done():
			log.Println("done")
			return
		default:
			log.Println("working")
		}
	}
}


func main() {
	log.Println("withCancel  start work!")
	withCancel()
	log.Println("withCancel  work over!")
	log.Println("----------------------------------------------")

	log.Println("withTimeout start work!")
	withTimeout()
	log.Println("withTimeout work over!")
	log.Println("----------------------------------------------")

	log.Println("withDeadline start work!")
	withDeadline()
	log.Println("withDeadline work over!")
	log.Println("----------------------------------------------")
}

   2.当parent取消时,所有子context取消


func main() {
	testCtx()
	time.Sleep(time.Minute*2)
}

func testCtx() {
	ctx,_ := context.WithTimeout(context.Background(),5*time.Second)
	//defer cancel()
	
	go func() {
		select {
		case <- ctx.Done():
			fmt.Println("ctx done:",time.Now())
		case <- time.After(time.Minute):
			fmt.Println("ctx timeout")
		}
	}()


	ctxChild1,_ := context.WithTimeout(ctx,10*time.Second)

	go func() {
		select {
		case <- ctxChild1.Done():
			fmt.Println("ctxChild1 done:",time.Now())
		case <- time.After(time.Minute):
			fmt.Println("ctxChild1 timeout")
		}
	}()


	ctxChild2,_ := context.WithTimeout(ctx,15*time.Second)
	go func() {
		select {
		case <- ctxChild2.Done():
			fmt.Println("ctxChild2 done:",time.Now())
		case <- time.After(time.Minute):
			fmt.Println("ctxChild2 timeout")
		}
	}()

	ctxDescendant , _  := context.WithCancel(ctxChild1)
	go func() {
		select {
		case <- ctxDescendant.Done():
			fmt.Println("ctxDescendant done:",time.Now())
		case <- time.After(time.Minute):
			fmt.Println("ctxDescendant timeout")
		}
	}()

}

   从结果可以看到当parent取消时,所有的子级context都会取消

参考地址:

https://www.jianshu.com/p/d24bf8b6c869?utm_campaign=studygolang.com&utm_medium=studygolang.com&utm_source=studygolang.com
https://www.jianshu.com/p/b7202f2bb477?utm_campaign=studygolang.com&utm_medium=studygolang.com&utm_source=studygolang.co

猜你喜欢

转载自blog.csdn.net/skh2015java/article/details/82111121