当前位置: 代码网 > it编程>前端脚本>Golang > go语言中context的使用说明

go语言中context的使用说明

2025年02月14日 Golang 我要评论
概述context 是 go 语言中非常重要的一个概念,它主要用于跨多个函数或 goroutine 传递 取消信号、超时控制、截止时间 和 请求范围数据。在并发编程中,context 提供了更好的控制

概述

context 是 go 语言中非常重要的一个概念,它主要用于跨多个函数或 goroutine 传递 取消信号超时控制截止时间请求范围数据

在并发编程中,context 提供了更好的控制和管理,尤其是当你需要在多个 goroutine 之间传递状态或进行资源清理时。

主要功能

context 主要有以下几个功能:

  • 取消信号:通知一个或多个 goroutine 取消它们正在执行的工作。
  • 超时和截止时间:指定操作的最大执行时间,防止阻塞操作过长时间。
  • 传递请求范围数据:携带请求范围内的数据,通常用于请求 id、用户信息等。

context 的三种基本类型

go 中的 context 包提供了几种常用的 context 类型:

  • context.background():通常作为根 context,表示没有附加数据或取消信号的上下文。它通常是根上下文,作为其他上下文的父上下文。
  • context.todo():表示你暂时没有确定使用什么样的 context,通常用于占位。
  • context.withcancel(parent):创建一个可取消的 context,并返回一个取消函数,当你调用这个函数时,context 会被取消。
  • context.withtimeout(parent, timeout):创建一个带有超时的 context,指定最大等待时间,超过这个时间会自动取消。
  • context.withdeadline(parent, deadline):指定一个具体的截止时间,超过这个时间后自动取消。
  • context.withvalue(parent, key, value):创建一个携带键值对数据的 context,通常用于传递请求级别的数据(例如,用户身份信息)。

常见用法举例

context.withcancel传递取消信号

主要场景:

  • 手动控制并发任务的终止
  • 优雅退出:在一个任务中途需要取消时,用 cancel() 通知所有相关的 goroutine 停止执行。

代码示例:

package main

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

func main() {
	// 创建一个可取消的 context
	ctx, cancel := context.withcancel(context.background())

	// 启动一个 goroutine,监听取消信号
	go func(ctx context.context) {
		for {
			select {
			case <-ctx.done(): // 检测到取消信号
				fmt.println("goroutine stopped")
				return
			default:
				// 模拟工作
				fmt.println("working...")
				time.sleep(1 * time.second)
			}
		}
	}(ctx)

	// 主线程等待 3 秒后取消
	time.sleep(3 * time.second)
	cancel() // 发送取消信号

	// 等待 goroutine 退出
	time.sleep(1 * time.second)
	fmt.println("main program exited")
}

解释

  1. 主线程创建了一个带有取消功能的上下文 ctx
  2. 子 goroutine 使用 ctx.done() 监听取消信号。
  3. 主线程 3 秒后调用 cancel(),子 goroutine 检测到信号后优雅退出。

使用 withtimeout 设置超时

context.withtimeout 用于设置一个超时时间,超过该时间后 context 会自动取消,适用于需要限时执行的操作。防止某些任务阻塞的时间过长。

package main

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

func main() {
	// 设置超时时间为 2 秒
	ctx, cancel := context.withtimeout(context.background(), 2*time.second)
	defer cancel() // 确保超时后取消 ctx

	// 启动一个模拟长时间执行的任务
	go longrunningtask(ctx)

	// 等待超时或任务完成
	<-ctx.done()
	if ctx.err() == context.deadlineexceeded {
		fmt.println("timeout reached")
	}
}

func longrunningtask(ctx context.context) {
	select {
	case <-time.after(3 * time.second): // 模拟长时间任务
		fmt.println("task completed")
	case <-ctx.done():
		// 任务被取消或超时
		fmt.println("task cancelled due to timeout")
	}
}

withdeadline的用法和withtimeout用法类似,只是一个传入的参数是等待时间,一个传入的参数是截止时间。

使用 withvalue 传递数据

context.withvalue 可以在 context 中存储键值对,通常用于传递请求级别的数据(例如用户身份、请求 id 等)。

package main

import (
	"context"
	"fmt"
)

func main() {
	// 创建一个上下文并传递数据
	ctx := context.withvalue(context.background(), "userid", 12345)

	// 将 ctx 传递给其他函数
	processrequest(ctx)
}

func processrequest(ctx context.context) {
	// 从 ctx 中提取数据
	userid := ctx.value("userid")
	if userid != nil {
		fmt.println("user id:", userid)
	} else {
		fmt.println("no user id found")
	}
}

使用 withvalue 小心context.withvalue 并不是用于传递大量数据的,主要用于传递少量的上下文信息,比如请求 id 等。

如果传递过多的数据,会使得 context 难以维护。

常用的相关方法和常量

  • ctx.done():返回一个 channel,当 context 被取消时该 channel 会被关闭。
  • ctx.err():返回 context 被取消的错误,通常是 context.canceledcontext.deadlineexceeded
  • ctx.value(key):获取在 context 中传递的数据。

context如何控制goroutine的执行

从上面的举例可以看出,在每个goroutine中通过判断ctx.done()是否被执行,从而知道任务是否被取消/超时/到达截止日期。

context 被取消(调用 cancel())或超时/到达截止时间时,ctx.done() 所关联的 channel 会关闭,此时select语句就可以执行ctx.done()对应的分支。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com