【一分钟快学】Go 语言中的 Context:管理取消信号、超时和值传递

想象一下,你正在一家快餐店等待你的订单。你的订单是由多个步骤组成的:首先是下单,然后是制作食物,最后是打包给你。在这个过程中,如果你决定取消订单,你希望快餐店立刻停止制作和打包,以节省时间和资源。这个"取消订单"的动作,就是 context 所做的事情。

context 是 Go 语言在 1.7 版本引入的一个标准库包,主要用来处理超时、取消操作和传递请求相关的值。它是一个为了让程序更加健壮、更容易管理而设计的功能。

context 做什么的?

  1. 取消信号 :它可以向所有使用同一个 context 的 goroutine 发送取消信号。这在你想要停止正在执行的操作时非常有用,比如说当用户取消了请求,或者操作已经超时了。
  2. 超时控制context 可以设定一个超时时间,一旦过了这个时间,就会自动发送取消信号。这对于控制那些可能会花费很长时间才能完成的操作特别有用。
  3. 值传递context 还可以用来传递请求范围内的数据,比如用户的身份信息、授权token等,这样在整个请求链中的任何一个环节都可以访问到这些信息。

怎么用?

使用 context 的典型模式是通过 context.Background()context.TODO() 创建一个根 context,然后通过 context.WithCancel()context.WithDeadline()context.WithTimeout()context.WithValue() 来派生出子 context

取消信号

go 复制代码
import (
    "context"
    "fmt"
    "time"
)

func main() {
    // 创建一个根context
    ctx, cancel := context.WithCancel(context.Background())
    
    // 在一个goroutine中使用这个context
    go func() {
        time.Sleep(2 * time.Second)
        // 2秒后发送取消信号
        cancel()
    }()
    
    // 等待取消信号
    <-ctx.Done()
    fmt.Println("Received cancel signal, shutting down...")
}

超时控制

go 复制代码
package main

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

func operation(ctx context.Context) {
    for {
        select {
        case <-time.After(3500 * time.Millisecond): // 模拟耗时的操作
            fmt.Println("operation finished")
        case <-ctx.Done():
            fmt.Println("operation cancelled")
            return
        }
    }
}

func main() {
    // 创建一个将在1秒后超时的context
    ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
    defer cancel() // 不要忘记调用cancel

    go operation(ctx)

    // 等待足够长的时间,以观察操作是否会因为超时而取消
    time.Sleep(2 * time.Second)
}

值传递

go 复制代码
package main

import (
    "context"
    "fmt"
)

func process(ctx context.Context) {
    // 从context中提取值
    if v := ctx.Value("key"); v != nil {
        fmt.Println("found value:", v)
        return
    }
    fmt.Println("value not found")
}

func main() {
    ctx := context.Background()
    // 使用context.WithValue来传递值
    ctx = context.WithValue(ctx, "key", "this is a value")

    process(ctx)
}
相关推荐
用户7713970207061 分钟前
从CMD到PowerShell:一个.NET开发者的命令行进化之路
后端
祎雪双十Gy3 分钟前
从 DataX 的配置加载说起:我用 FastJson2 做了一个轻量级动态配置管理库
java·后端
Csvn2 小时前
Nginx 配置与运维管理 — 从安装到 SSL 反向代理
后端
mqcode3 小时前
若依框架做大了怎么办?多模块 Maven 拆分的完整指南
后端
用户40269244819083 小时前
CRMEB Pro 新增后台接口全链路:路由、权限、验证器、返回格式一次讲清
前端·后端
考虑考虑3 小时前
Java实现hmacsha1加密算法
java·后端·java ee
程序边界4 小时前
lac_agent自愈链路上篇——crontab守护的那些坑与健康检查实战
后端
笨鸟飞不快4 小时前
从 MVC 到 DDD:一次真实的渐进式迁移实录
后端·架构
程序员威哥4 小时前
C#也能玩转YOLO:工业视觉原生推理方案,零Python依赖
后端
kfaino4 小时前
你好,我叫 Prompt——其实,你一直在给 AI 写程序
后端·openai·ai编程