【一分钟快学】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)
}
相关推荐
程序员爱钓鱼2 小时前
GoHTML解析利器:github.com/PuerkitoBio/goquery实战指南
后端·google·go
golang学习记2 小时前
从“大泥球“到模块化单体:Spring Modulith + IntelliJ IDEA 拯救你的代码
后端·intellij idea
颜酱2 小时前
一步步实现字符串计算器:从「转整数」到「带括号与优化」
javascript·后端·算法
离开地球表面_993 小时前
金三银四程序员跳槽指南:从简历到面试再到 Offer 的全流程准备
前端·后端·面试
UrbanJazzerati3 小时前
Scrapling入门指南:零基础也能学会的网页抓取神器
后端·面试
张洪权3 小时前
mysql + nest.js 加锁 搞并发问题
后端
郡杰3 小时前
MyBatisPlus
后端
beata3 小时前
Java基础-18:Java开发中的常用设计模式:深入解析与实战应用
java·后端
Qlly3 小时前
DDD 架构为什么适合 MCP Server 开发?
人工智能·后端·架构
苏三说技术3 小时前
Prompt、Agent、Function Call、Skill、MCP,傻傻分不清楚?
后端