当前位置:首页 > 科技  > 软件

Go语言高级特性:Context深入解读

来源: 责编: 时间:2023-11-01 09:18:43 373观看
导读概述在 Go 语言中,context(上下文)是一个非常重要的概念。它主要用于在多个 goroutine 之间传递请求特定任务的截止日期、取消信号以及其他请求范围的值。3. Context 的取消与超时本文将探讨 Go 语言中context的用法,从基

概述

在 Go 语言中,context(上下文)是一个非常重要的概念。HGg28资讯网——每日最新资讯28at.com

它主要用于在多个 goroutine 之间传递请求特定任务的截止日期、取消信号以及其他请求范围的值。3. Context 的取消与超时HGg28资讯网——每日最新资讯28at.com

本文将探讨 Go 语言中context的用法,从基础概念到实际应用,将全面了解上下文的使用方法。HGg28资讯网——每日最新资讯28at.com

主要内容包括HGg28资讯网——每日最新资讯28at.com

什么是 Context(上下文)HGg28资讯网——每日最新资讯28at.com

Context 的基本用法:创建与传递HGg28资讯网——每日最新资讯28at.com

Context 的取消与超时HGg28资讯网——每日最新资讯28at.com

Context 的值传递HGg28资讯网——每日最新资讯28at.com

实际应用场景:HTTP 请求的 Context 使用HGg28资讯网——每日最新资讯28at.com

数据库操作中的 Context 应用HGg28资讯网——每日最新资讯28at.com

自定义 Context 的实现HGg28资讯网——每日最新资讯28at.com

Context 的生命周期管理HGg28资讯网——每日最新资讯28at.com

Context 的注意事项HGg28资讯网——每日最新资讯28at.com

1. 什么是 Context(上下文)

在 Go 语言中,context(上下文)是一个接口,定义了四个方法:Deadline()、Done()、Err()和Value(key interface{})。HGg28资讯网——每日最新资讯28at.com

它主要用于在 goroutine 之间传递请求的截止日期、取消信号以及其他请求范围的值。HGg28资讯网——每日最新资讯28at.com

2. Context 的基本用法:创建与传递

2.1 创建 Context

package mainimport (  "context"  "fmt")func main() {  // 创建一个空的Context  ctx := context.Background()  // 创建一个带有取消信号的Context  _, cancel := context.WithCancel(ctx)  defer cancel() // 延迟调用cancel,确保在函数退出时取消Context  fmt.Println("Context创建成功")}

以上代码演示了如何创建一个空的context和一个带有取消信号的context。HGg28资讯网——每日最新资讯28at.com

使用context.WithCancel(parent)可以创建一个带有取消信号的子context。HGg28资讯网——每日最新资讯28at.com

在调用cancel函数时,所有基于该context的操作都会收到取消信号。HGg28资讯网——每日最新资讯28at.com

2.2 传递 Context

package mainimport (  "context"  "fmt"  "time")func worker(ctx context.Context) {  for {    select {    case <-ctx.Done():      fmt.Println("收到取消信号,任务结束")      return    default:      fmt.Println("正在执行任务...")      time.Sleep(1 * time.Second)    }  }}func main() {  ctx := context.Background()  ctxWithCancel, cancel := context.WithCancel(ctx)  defer cancel()  go worker(ctxWithCancel)  time.Sleep(3 * time.Second)  cancel() // 发送取消信号  time.Sleep(1 * time.Second)}

在上面例子中,创建了一个带有取消信号的context,并将它传递给一个 goroutine 中的任务。HGg28资讯网——每日最新资讯28at.com

调用cancel函数,可以发送取消信号,中断任务的执行。HGg28资讯网——每日最新资讯28at.com

3.Context 的取消与超时

3.1 使用 Context 实现取消

package mainimport (  "context"  "fmt"  "time")func main() {  ctx := context.Background()  ctxWithCancel, cancel := context.WithCancel(ctx)  go func() {    select {    case <-ctxWithCancel.Done():      fmt.Println("收到取消信号,任务结束")    case <-time.After(2 * time.Second):      fmt.Println("任务完成")    }  }()  time.Sleep(1 * time.Second)    cancel() // 发送取消信号    time.Sleep(1 * time.Second)}

在这个例子中,使用time.After函数模拟一个长时间运行的任务。HGg28资讯网——每日最新资讯28at.com

如果任务在 2 秒内完成,就打印“任务完成”,否则在接收到取消信号后打印“收到取消信号,任务结束”。HGg28资讯网——每日最新资讯28at.com

3.2 使用 Context 实现超时控制

package mainimport (  "context"  "fmt"  "time")func main() {  ctx := context.Background()    ctxWithTimeout, cancel := context.WithTimeout(ctx, 2*time.Second)    defer cancel()  select {  case <-ctxWithTimeout.Done():    fmt.Println("超时,任务结束")  case <-time.After(1 * time.Second):    fmt.Println("任务完成")  }}

在上面例子中,使用context.WithTimeout(parent, duration)函数创建了一个在 2 秒后自动取消的contextHGg28资讯网——每日最新资讯28at.com

如果任务在 1 秒内完成,就打印“任务完成”,否则在 2 秒后打印“超时,任务结束”。HGg28资讯网——每日最新资讯28at.com

4. Context 的值传递

4.1 使用 WithValue 传递值

package mainimport (  "context"  "fmt")type key stringfunc main() {  ctx := context.WithValue(context.Background(), key("name"), "Alice")  value := ctx.Value(key("name"))  fmt.Println("Name:", value)}

在上面例子中,使用context.WithValue(parent, key, value)函数在context中传递了一个键值对。HGg28资讯网——每日最新资讯28at.com

使用ctx.Value(key)函数可以获取传递的值。HGg28资讯网——每日最新资讯28at.com

5. 实际应用场景:HTTP 请求的 Context 使用

5.1 使用 Context 处理 HTTP 请求

package mainimport (  "fmt"  "net/http"  "time")func handler(w http.ResponseWriter, r *http.Request) {  ctx := r.Context()  select {  case <-time.After(3 * time.Second):    fmt.Fprintln(w, "Hello, World!")  case <-ctx.Done():    err := ctx.Err()    fmt.Println("处理请求:", err)    http.Error(w, err.Error(), http.StatusInternalServerError)  }}func main() {  http.HandleFunc("/", handler)  http.ListenAndServe(":8080", nil)}

在上面例子中,使用http.Request结构体中的Context()方法获取到请求的context,并在处理请求时设置了 3 秒的超时时间。HGg28资讯网——每日最新资讯28at.com

如果请求在 3 秒内完成,就返回“Hello, World!”,否则返回一个错误。HGg28资讯网——每日最新资讯28at.com

5.2 处理 HTTP 请求的超时与取消

package mainimport (  "context"  "fmt"  "net/http"  "time")func handler(w http.ResponseWriter, r *http.Request) {  ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)  defer cancel()  select {  case <-time.After(3 * time.Second):    fmt.Fprintln(w, "Hello, World!")  case <-ctx.Done():    err := ctx.Err()    fmt.Println("处理请求:", err)    http.Error(w, err.Error(), http.StatusInternalServerError)  }}func main() {  http.HandleFunc("/", handler)  http.ListenAndServe(":8080", nil)}

在上面例子中,使用context.WithTimeout(parent, duration)函数为每个请求设置了 2 秒的超时时间。HGg28资讯网——每日最新资讯28at.com

如果请求在 2 秒内完成,就返回“Hello, World!”,否则返回一个错误。HGg28资讯网——每日最新资讯28at.com

6. 数据库操作中的 Context 应用

6.1 使用 Context 控制数据库查询的超时

package mainimport (  "context"  "database/sql"  "fmt"  "time"  _ "github.com/go-sql-driver/mysql")func main() {  db, err := sql.Open("mysql", "username:password@tcp(localhost:3306)/database")    if err != nil {    fmt.Println(err)    return  }    defer db.Close()  ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)    defer cancel()  rows, err := db.QueryContext(ctx, "SELECT * FROM users")    if err != nil {    fmt.Println("查询出错:", err)    return  }    defer rows.Close()  // 处理查询结果}

在上面例子中,使用context.WithTimeout(parent, duration)函数为数据库查询设置了 2 秒的超时时间,确保在 2 秒内完成查询操作。HGg28资讯网——每日最新资讯28at.com

如果查询超时,程序会收到context的取消信号,从而中断数据库查询。HGg28资讯网——每日最新资讯28at.com

6.2 使用 Context 取消长时间运行的数据库事务

package mainimport (  "context"  "database/sql"  "fmt"  "time"  _ "github.com/go-sql-driver/mysql")func main() {  db, err := sql.Open("mysql", "username:password@tcp(localhost:3306)/database")    if err != nil {    fmt.Println(err)    return  }  defer db.Close()  tx, err := db.Begin()  if err != nil {    fmt.Println(err)    return  }  ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)    defer cancel()  go func() {    <-ctx.Done()        fmt.Println("接收到取消信号,回滚事务")        tx.Rollback()  }()  // 执行长时间运行的事务操作  // ...  err = tx.Commit()  if err != nil {      fmt.Println("提交事务出错:", err)        return  }  fmt.Println("事务提交成功")}

在这个例子中,使用context.WithTimeout(parent, duration)函数为数据库事务设置了 2 秒的超时时间。HGg28资讯网——每日最新资讯28at.com

同时使用 goroutine 监听context的取消信号。HGg28资讯网——每日最新资讯28at.com

在 2 秒内事务没有完成,程序会收到context的取消信号,从而回滚事务。HGg28资讯网——每日最新资讯28at.com

7. 自定义 Context 的实现

7.1 实现自定义的 Context 类型

package mainimport (  "context"  "fmt"  "time")type MyContext struct {  context.Context  RequestID string}func WithRequestID(ctx context.Context, requestID string) *MyContext {  return &MyContext{    Context:   ctx,    RequestID: requestID,  }}func (c *MyContext) Deadline() (deadline time.Time, ok bool) {  return c.Context.Deadline()}func (c *MyContext) Done() <-chan struct{} {  return c.Context.Done()}func (c *MyContext) Err() error {  return c.Context.Err()}func (c *MyContext) Value(key interface{}) interface{} {  if key == "requestID" {    return c.RequestID  }  return c.Context.Value(key)}func main() {  ctx := context.Background()    ctxWithRequestID := WithRequestID(ctx, "12345")  requestID := ctxWithRequestID.Value("requestID").(string)    fmt.Println("Request ID:", requestID)}

在这个例子中,实现了一个自定义的MyContext类型,它包含了一个RequestID字段。HGg28资讯网——每日最新资讯28at.com

通过WithRequestID函数,可以在原有的context上附加一个RequestID值,然后在需要的时候获取这个值。HGg28资讯网——每日最新资讯28at.com

7.2 自定义 Context 的应用场景

自定义context类型的应用场景非常广泛,比如在微服务架构中,HGg28资讯网——每日最新资讯28at.com

可在context中加入一些额外的信息,比如用户 ID、请求来源等,以便在服务调用链路中传递这些信息。HGg28资讯网——每日最新资讯28at.com

8. Context 的生命周期管理

8.1 Context 的生命周期

context.Context 是不可变的,一旦创建就不能修改。它的值在传递时是安全的,可以被多个 goroutine 共享。HGg28资讯网——每日最新资讯28at.com

在一个请求处理的生命周期内,通常会创建一个顶级的 Context,然后从这个顶级的 Context 派生出子 Context,传递给具体的处理函数。HGg28资讯网——每日最新资讯28at.com

8.2 Context 的取消

当请求处理完成或者发生错误时,应该主动调用 context.WithCancel 或 context.WithTimeout 等函数创建的 Context 的 Cancel 函数来通知子 goroutines 停止工作。HGg28资讯网——每日最新资讯28at.com

这样可以确保资源被及时释放,避免 goroutine 泄漏。HGg28资讯网——每日最新资讯28at.com

func handleRequest(ctx context.Context) {    // 派生一个新的 Context,设置超时时间    ctx, cancel := context.WithTimeout(ctx, time.Second)        defer cancel() // 确保在函数退出时调用 cancel,防止资源泄漏    // 在这个新的 Context 下进行操作    // ...}

8.3 Context 的传递

在函数之间传递 Context 时,确保传递的是必要的最小信息。避免在函数间传递整个 Context,而是选择传递 Context 的衍生物。HGg28资讯网——每日最新资讯28at.com

如 context.WithValue 创建的 Context,其中包含了特定的键值对信息。HGg28资讯网——每日最新资讯28at.com

func middleware(next http.Handler) http.Handler {return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {// 从请求中获取特定的信息userID := extractUserID(r)// 将特定的信息存储到 Context 中ctx := context.WithValue(r.Context(), userIDKey, userID)// 将新的 Context 传递给下一个处理器next.ServeHTTP(w, r.WithContext(ctx))})}

9. Context 的注意事项

9.1 不要在函数签名中传递 Context

避免在函数的参数列表中传递 context.Context,除非确实需要用到它。HGg28资讯网——每日最新资讯28at.com

如果函数的逻辑只需要使用 Context 的部分功能,那么最好只传递它需要的具体信息,而不是整个 Context。HGg28资讯网——每日最新资讯28at.com

// 不推荐的做法func processRequest(ctx context.Context) {    // ...}// 推荐的做法func processRequest(userID int, timeout time.Duration) {    // 使用 userID 和 timeout,而不是整个 Context}

9.2 避免在结构体中滥用 Context

不要在结构体中保存 context.Context,因为它会增加结构体的复杂性。HGg28资讯网——每日最新资讯28at.com

若是需要在结构体中使用 Context 的值,最好将需要的值作为结构体的字段传递进来。HGg28资讯网——每日最新资讯28at.com

type MyStruct struct {    // 不推荐的做法    Ctx context.Context        // 推荐的做法    UserID int}

本文链接:http://www.28at.com/showinfo-26-16279-0.htmlGo语言高级特性:Context深入解读

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: Spring事件机制,深入剖析,提升你的技术水平!

下一篇: Python 中的 IS 和 == 运算符有什么区别?

标签:
  • 热门焦点
  • 一加Ace2 Pro真机揭晓 钛空灰配色质感拉满

    终于,在经过了几波预热之后,一加Ace2 Pro的外观真机图在网上出现了。还是博主数码闲聊站曝光的,这次的外观设计还是延续了一加11的方案,只是细节上有了调整,例如新加入了钛空灰
  • 官方承诺:K60至尊版将会首批升级MIUI 15

    全新的MIUI 15今天也有了消息,在官宣了K60至尊版将会搭载天玑9200+处理器和独显芯片X7的同时,Redmi给出了官方承诺,K60至尊重大更新首批升级,会首批推送MIUI 15。也就是说虽然
  • 之家push系统迭代之路

    前言在这个信息爆炸的互联网时代,能够及时准确获取信息是当今社会要解决的关键问题之一。随着之家用户体量和内容规模的不断增大,传统的靠"主动拉"获取信息的方式已不能满足用
  • 三分钟白话RocketMQ系列—— 如何发送消息

    我们知道RocketMQ主要分为消息 生产、存储(消息堆积)、消费 三大块领域。那接下来,我们白话一下,RocketMQ是如何发送消息的,揭秘消息生产全过程。注意,如果白话中不小心提到相关代
  • 零售大模型“干中学”,攀爬数字化珠峰

    文/侯煜编辑/cc来源/华尔街科技眼对于绝大多数登山爱好者而言,攀爬珠穆朗玛峰可谓终极目标。攀登珠峰的商业路线有两条,一是尼泊尔境内的南坡路线,一是中国境内的北坡路线。相
  • 2023年,我眼中的字节跳动

    此时此刻(2023年7月),字节跳动从未上市,也从未公布过任何官方的上市计划;但是这并不妨碍它成为中国最受关注的互联网公司之一。从2016-17年的抖音强势崛起,到2018年的&ldquo;头腾
  • 消息称小米汽车开始筛选交付中心:需至少120个车位

    IT之家 7 月 7 日消息,日前,有微博简介为“汽车行业从业者、长三角一体化拥护者”的微博用户 @长三角行健者 发文表示,据经销商集团反馈,小米汽车目前
  • 2022爆款:ROG魔霸6 冰川散热系统持续护航

    喜逢开学季,各大商家开始推出自己的新产品,进行打折促销活动。对于忠实的端游爱好者来说,能够拥有一款梦寐以求的笔记本电脑是一件十分开心的事。但是现在的
  • 由于成本持续增加,笔记本产品价格预计将明显上涨

    根据知情人士透露,由于材料、物流等成本持续增加,笔记本产品价格预计将在2021年下半年有明显上涨。进入6月下旬以来,全球半导体芯片缺货情况加剧,显卡、处理器
Top