【一分钟快学】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)
}
相关推荐
qq_297574677 小时前
【实战教程】SpringBoot 实现多文件批量下载并打包为 ZIP 压缩包
java·spring boot·后端
计算机程序设计小李同学15 小时前
基于 Spring Boot + Vue 的龙虾专营店管理系统的设计与实现
java·spring boot·后端·spring·vue
Charlie_lll17 小时前
力扣解题-[3379]转换数组
数据结构·后端·算法·leetcode
VX:Fegn089517 小时前
计算机毕业设计|基于springboot + vue云租车平台系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
汤姆yu18 小时前
2026基于springboot的在线招聘系统
java·spring boot·后端
计算机学姐18 小时前
基于SpringBoot的校园社团管理系统
java·vue.js·spring boot·后端·spring·信息可视化·推荐算法
hssfscv18 小时前
Javaweb学习笔记——后端实战8 springboot原理
笔记·后端·学习
咚为18 小时前
Rust tokio:Task ≠ Thread:Tokio 调度模型中的“假并发”与真实代价
开发语言·后端·rust
Anastasiozzzz19 小时前
对抗大文件上传---分片加多重Hash判重
服务器·后端·算法·哈希算法
Vivienne_ChenW19 小时前
DDD领域模型在项目中的实战
java·开发语言·后端·设计模式