Golang Context包的使用

context包主要用来控制goroutings间的并发控制。使用场景包括通知子协程退出这种。

相关接口和示例:

func Background() Context
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.

该函数返回一个空的ctx,该ctx不能被取消,没有值并且没有deadline。通常用于主函数、初始化或者测试中,用作顶层的ctx。

func TODO() Context
TODO returns a non-nil, empty Context. Code should use context.TODO when it's unclear which Context to use 
or it is not yet available (because the surrounding function has not yet been extended to accept 
a Context parameter).

TODO方法和Background方法的实现以一样的,区别在于TODO能够被静态分析工具识别。

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

WithCancel returns a copy of parent with a new Done channel. The returned context's Done channel is closed 
when the returned cancel function is called or when the parent context's Done channel is closed, whichever 
happens first.

WithCancel 返回父ctx的一份复制和一个新的Done 通道,返回的ctx Done通道只有在cancel方法被调用或者父ctx被取消才返回。

withCancel示例一,调用cancel方法通知子协程取消:

package main

import (
	"context"
	"fmt"
	"time"
)

func main() {
	//定义一个空的ctx
	rootCtx := context.TODO()

	//从根ctx衍生子ctx
	ctx, cancel := context.WithCancel(rootCtx)
	go func() {
		for {
			select {
			case <-ctx.Done():
				fmt.Printf("cancel called, gorouting exit\n")
				return
			case <-time.After(1 * time.Second):
				fmt.Println("gorouting running...")
			}
		}
	}()
	fmt.Println("main routing sleep 3s")
	time.Sleep(time.Second * 3)
	//调用cancel取消子线程
	cancel()
	fmt.Println("main routing call cancel")
	time.Sleep(1 * time.Second)
}

运行截图:

 

withCancel示例二,取消父ctx,子协程一并退出:

package main

import (
	"context"
	"fmt"
	"time"
)

func main() {
	//建立一个父context
	parentCtx, cancel := context.WithCancel(context.Background())
	go func() {
		//从父context衍生出子context
		childCtx, _ := context.WithCancel(parentCtx)
		go func() {
			//子协程运行
			for {
				select {
				case <-childCtx.Done():
					fmt.Printf("childCtx Done, Child exit\n")
					return
				case <-time.After(time.Second * 2):
					fmt.Println("Child is running...")
				}
			}
		}()

		//父协程运行
		for {
			select {
			case <-parentCtx.Done():
				fmt.Println("parentCtx Done, Parent exit")
				return
			case <-time.After(time.Second * 6):
				fmt.Println("parent is running...")
			}
		}
	}()

	time.Sleep(8 * time.Second)

	fmt.Printf("Time Up, Close parentCtx\n")
	//取消父context
	cancel()
	time.Sleep(4 * time.Second)
}

运行截图:

 

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

WithDeadline和withCancel类似,只不过增加了一个截止时间,时间到了,该ctx的Done通道会自动关闭。

WithDeadline用例:

package main

import (
	"context"
	"fmt"
	"time"
)

func main() {

	//衍生一个3s的ctx
	ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Second*3))
	//好的编码习惯是主动调用cancel,即便ctx自动超时过期。
	defer cancel()

	for {
		select {
		case <-ctx.Done():
			fmt.Println("ctx Done")
			return
		case <-time.After(1 * time.Second):
			fmt.Println("time up...")
		}
	}
}

运行截图:

 

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

WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).

这个方法和WithDeadline类似
func WithValue(parent Context, key, val interface{}) Context

WithValue方法可以绑定一个键值对,使得后续衍生出来的ctx都能够获取这个值。

WithValue返回父类的副本,其中与键关联的值为val。

仅对传输流程和api的请求范围的数据使用上下文值,而不是将可选参数传递给函数。

所提供的键必须是可比较的,并且不应该是string类型或任何其他内置类型,以避免使用上下文在包之间发
生冲突。WithValue的用户应该为键定义自己的类型。为了避免在分配给接口{}时进行分配,上下文键通常
具有具体类型struct{}。或者,导出的上下文关键变量的静态类型应该是指针或接口。

WithValue用例:

package main

import (
	"context"
	"fmt"
)

func main() {
	type ContextKey string

	f := func(ctx context.Context, k ContextKey) {
		if v := ctx.Value(k); v != nil {
			fmt.Println("found value:", v)
			return
		}
		fmt.Println("key not found:", k)
	}

    //绑定键值对{"language":"Go"}
	k := ContextKey("language")
	ctx := context.WithValue(context.Background(), k, "Go")

	f(ctx, k)
	f(ctx, ContextKey("color"))

}

运行截图:

 

参考资料:

1.https://golang.org/pkg/context/

2. Go语言实战笔记(二十)| Go Context,https://www.flysnow.org/2017/05/12/go-in-action-go-context.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值