Golang上下文context

news/2024/10/11 16:13:14

上篇内容我们主要讲解了net/http标准库的使用,其中包含如何创建POST请求、GET请求以及如何携带参数的请求。

Context介绍

context释义为上下文,在我们使用goroutine时一般使用context来进行元数据的传递,非元数据不建议使用context来进行传递。那么我们主要是用context用来做什么呢?其实我们主要是是用来在多个goroutine中传递取消信号,调用链路信息等。

使用建议

  1. 不要在结构体中存储context,将context类型作为函数的第一个参数,一般命名为ctx

  2. 不要向函数中传递nilcontext,如果不知道使用那个可以使用TODO进行占位使用都一样。

  3. 不要将函数所需的非元数据塞到context中。

  4. 同一个context可能会被传递到多个goroutine中,context对于多个goroutine是安全的。

context接口

type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key interface{}) interface{}
}

context方法

我们可以看到context接口中有四个方法。

  • Deadline():返回值deadline表示当前context应该结束的时间,例如2sok表示是否有结束时间。

  • Done():返回一个只读的单向channel,当超时或者调用cancel(创建子context的一个返回函数)方法时,将会触发该方法。

  • Err():context被取消的原因。

  • Value():context共享数据存储。

创建根(父)context

  • context.Background():返回一个非nil的空context,没有任何值,不会被cancel,不会超时,没有截至日期。

  • context.TODO():返回一个非nil的 空context,没有任何值,不会被cancel,不会超时,没有截至日期。当不知道使用那个context时,用它。

图片

创建子context

  • WithValue:通过该函数可以在context中传递键值对,用于跨goroutine传递请求范围的值,但是要注意,这不是用于传递请求相关数据的首选方法,而是应该用于传递相关元数据。

    图片

  • WithCancle:通过该函数可以创建一个可取消的context并返回一个新的context和一个cancelFunc。当调用CancelFunc时,与该context相关联的所有goroutines都会收到取消信号.

    图片

  • WithTimeout:通过该函数可以创建一个带有超时时间的context。在指定的时间后过期,context会自动取消 。不要忘记defer cancel()

    图片

  • WithDeadline:通过该函数可以创建一个带有特定截至时间的context,在截至时间之后context会自动取消  不要忘记defer cancel()哦。

    图片

案例演示

WithValue

package main

import (
"context"
"fmt"
)

func main() {
parentContext := context.Background()
ctx1 := context.WithValue(parentContext, "key1", "value1")
ctx11 := context.WithValue(ctx1, "key11", "value11")
// 这里的儿子与孙子都是基于parentContext来说的哦
fmt.Println("儿子的money:", ctx1.Value("key1"))
fmt.Println("儿子将money给孙子了:", ctx11.Value("key1"))
fmt.Println("孙子个人money:", ctx11.Value("key11"))
fmt.Println("孙子想要儿子的money:", ctx1.Value("key11"))
}

运行结果为:

儿子的money: value1
儿子将money给孙子了: value1
孙子个人money: value11
孙子想要儿子的money: <nil>

说明:通过上边的案例我们应该可以看懂context中的value传递。

WithCancle

package main

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

func main() {
// 这样写不要看不懂哦,只是将父context直接传入了
ctx, cancel := context.WithCancel(context.Background())
go fun1(ctx)
time.Sleep(6 * time.Second)
fmt.Println("使用cancel停止goroutine")
cancel()
time.Sleep(2 * time.Second)
fmt.Println("main")
}

func fun1(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("goroutine退出了哦", ctx.Err())
return
default:
fmt.Println("goroutine持续运行中")
time.Sleep(2 * time.Second)
}
}

}

运行结果为:

goroutine持续运行中
goroutine持续运行中
goroutine持续运行中
使用cancel停止goroutine
goroutine退出了哦 context canceled
main

说明:从上述运行结果我们可以看出,当调用cancelgoroutine停止了。并打印了退出的原因(ctx.Err())。

WithTimeout

package main

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

func main() {
// 这样写不要看不懂哦,只是将父context直接传入了
ctx, cancel := context.WithTimeout(context.Background(), 6*time.Second)
go fun1(ctx)
time.Sleep(18 * time.Second)
defer cancel()
time.Sleep(2 * time.Second)
fmt.Println("main")
}

func fun1(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("goroutine退出了哦", ctx.Err())
return
default:
time.Sleep(2 * time.Second)
fmt.Println("goroutine持续运行中")

}
}

}

运行结果为:

goroutine持续运行中
goroutine持续运行中
goroutine持续运行中
goroutine退出了哦 context deadline exceeded
main

说明:通过上述代码的运行结果我们可以发现,当运行超过我们设置的时间(6*time.Second)时,会取消goroutine的运行,这也是我们打印的结果为什么时3goroutine持续运行中

WithDeadline

package main

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

func main() {
// 这样写不要看不懂哦,只是将父context直接传入了
d := time.Now().Add(6 * time.Second)
ctx, cancel := context.WithDeadline(context.Background(), d)
go fun1(ctx)
defer cancel()
time.Sleep(10 * time.Second)
fmt.Println("main")
}

func fun1(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("goroutine退出了哦", ctx.Err())
return
default:
time.Sleep(2 * time.Second)
fmt.Println("goroutine持续运行中")

}
}

}

运行结果为:

goroutine持续运行中
goroutine持续运行中
goroutine持续运行中
goroutine退出了哦 context deadline exceeded
main

说明:根据打印结果我们可以发现,其实WithDeadlineWithTimeout差不多,只不过WithTimeout设置的是运行的时间,而WithDeadline表示goroutine运行到那个时间节点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/70259.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

2024 最新 IntelliJ IDEA 2024.1.6 激活(亲测可用)

注意:接下来本文分享免费激活 IDEA 等Jetbrains全家桶工具,一直支持到最新版本2024.1.6。 1.下载安装IDEA (mac、window、linux都支持) 大家直接在官网下载最新版本,登陆官网,下载最新版本2024.1.4。一步一步确定安装,然后打开 这里提示输入激活码,先关闭应用!!!2.…

淘宝程序员没活硬整?在 Excel 和 VSCode 中购物!

你可以在 Excel 表格中挑选商品进行购物,还原度极高,这两个图表更是点睛之笔。哪个天才想出来的,把特么广告都整成了 Excel 图表。大家好,我是程序员鱼皮,最近某宝网站的改进,属实是有点 “新” 了。 你敢相信这是一个购物网站么?你可以在 Excel 表格中挑选商品进行购物…

Golang模板template

背景概述 当我们在进行json字段选取以及渲染时,我们经常会见到{{}},其实这就是我们今天要讲解的模板即是template。例如prometheusAlert中的模板就是使用了改语法。 必备技能字段选取 ❝ {{ . }} 表示json的所有域,例如:{"name":"anruo","age&quo…

如何在springboot中,全局配置produces=text/plain;charset=UTF-8

为什么要使用produces="text/plain;charset=UTF-8"? 当不用这个配置时,接口返回的数据,是有斜杠的 配置后,就正常了 以前我的配置方式,是在每个接口上,都添加上produces="text/plain;charset=UTF-8"。但是这样显示不太好,每个接口都加的话,会比较…

鸿蒙发送消息通知

注意:发送消息通知要开启设置中的消息通知import notify from @ohos.notificationManager import image from @ohos.multimedia.image import { BusinessError } from @kit.BasicServicesKit@Entry @Component struct NotificationPage {// 全局任务ididx: number = 100// 图象…

域名解析错误是不是被限制了?

在我们畅游互联网的过程中,有时会遭遇域名解析错误的情况,这无疑会给我们的上网体验带来困扰。而很多人在遇到域名解析错误时,不禁会疑惑:这是不是意味着被限制了呢? 首先,域名解析错误并不一定意味着被限制。 域名解析是将域名转换为对应的IP地址的过程,就如同在电话簿…

Xshell:需要Xmanager软件来处理X11转发请求.....

关闭这个连接,然后重新连接即可。本文来自博客园,作者:__username,转载请注明原文链接:https://www.cnblogs.com/code3/p/18458533