Golang中的Context有什么用? | 青训营

159 阅读2分钟

Golang中的Context

当我们学习golang时,总会看见context这个词(比如gin.Context),但是总感觉context好像没什么用,那context有什么用?该怎么用?

go语言Context的定义

在 Go 语言中,context 是一种用于跨 API 和进程传递取消信号、超时和截止时间的机制。它可以用来管理一个请求的上下文信息,并在需要的时候进行取消操作,以便释放资源或终止操作。context 包提供了一个 Context 类型以及一些相关的函数,用于创建、传递和取消上下文。

type Context interface {
	Deadline() (deadline time.Time, ok bool)
	Done() <-chan struct{}//返回一个只读管道
	Err() error //当执行Done时,记录为什么关闭
	Value(key any) any //用于传入Key-Value和通过Key取出Value
}

创建一个空的context

golang提供了两个方法来创建一个Context,Todo和Background,他们都返回一个空的Context,作为我们最开始的Context来进行传递。

context := context.Background()

用法一: 传递Key-Value

在函数执行过程中,我们可以通过context在函数调用过程中的传递,来设置或者获取Key-Value。

示例代码

func step1(ctx context.Context) context.Context {
	child := context.WithValue(ctx, "name", "小白")
	return child
}

func step2(ctx context.Context) context.Context {
	child := context.WithValue(ctx, "age", "18")
	return child
}

func step3(ctx context.Context) {
	fmt.Printf("name %s age %s",ctx.Value("name"),ctx.Value("age"))
}

func main() {
	//实现一个空Context,最开始的context
	grandpa := context.Background()

	father := step1(grandpa)
	grandson := step2(father)
	step3(grandson)
}

这段代码的输出结果为name 小白 age 18, 成功的从context中获取到了传递的值。

用法二: 截止时间和超时

可以在 Context 中设置截止时间,一旦超过指定的时间,Context 会自动取消。这对于避免某些操作无限期地等待非常有用。

示例代码

func f1() {
	ctx,cancel := context.WithTimeout(context.TODO(),time.Millisecond * 100)
	defer cancel()
	select {
	case <-ctx.Done():
		err := ctx.Err().Error()
		println(err)
	}
}

func main() {
	f1()
}

在上面的代码中我们创建了一个超时时间为100ms的context,当超时,会自动调用Done函数,我们通过select捕获,并打印出调用原因。 这段代码的输出为context deadline exceeded, 注意,调用Done函数取决于context调用过程中寿命最短的那个。

用法三: 取消操作

当一个操作需要在某个条件满足或者超过一定时间后终止时,context 可以通过传递取消信号来实现。这对于在超时、用户请求取消或错误发生时,能够及时中止操作并释放资源非常有用。

示例代码

func f2() {
	ctx,cancel := context.WithCancel(context.TODO())
	start := time.Now()
	go func() {
		time.Sleep(time.Millisecond * 100)
		cancel()
	}()

	select {
	case <- ctx.Done():
		end := time.Now()
		fmt.Println(end.Sub(start).Milliseconds())
		err := ctx.Err().Error()
		println(err)
	}
}

func main() {
	f2()
}

在这段代码中,我们创建了一个取消操作的context,当我们主动执行cancel函数时,会触发Done函数,停止context。这段代码的输出为112 context canceled