Go Context 有什么作用,如何实现多级传递?

考查重点:取消、截止与调用树传递。父Context派生带超时/取消子Context,沿调用传递,子检查Done;defer cancel释放资源,值只放请求级元数据

本题目录

参考答案

核心回答

Go 的 context.Context 用于沿一次请求的调用链传递取消信号、截止时间和请求级元数据。例如入口请求不再需要结果时,数据库查询、下游调用和相关 goroutine 可以通过同一条 Context 链收到通知,及时停止无用工作。

多级传递靠显式传参:Handler 把 ctx 传给 Service,Service 再传给 Repo;启动新 goroutine 时也要显式传入。通常把它作为函数的第一个参数,需要独立控制一个分支时,再从父 ctx 派生子 Context:

  • WithCancel:增加可主动取消的作用域。
  • WithDeadline、WithTimeout:增加截止时间或相对超时;子级不能把父级截止时间往后延长。
  • WithValue:附加 Trace ID 等请求级信息,下游可以沿派生链读取。

在这样的派生链中,父级取消会通知其下的子级;取消某个子级不会反向取消父级和其他分支。取消是协作通知,不会强行杀死 goroutine,也不会等待任务退出。 任务要监听 ctx.Done(),或把 ctx 交给支持取消的 I/O 接口,才能作出响应。

多级调用怎样安排超时

例如一次请求经过 Handler → Service → Repo。入口从请求本身取得 ctx,Service 继续传递,Repo 为一次查询派生 200ms 的子超时,并把子 ctx 传给数据库调用。

如果此时父级只剩 80ms,查询仍受父级约束,不会重新获得完整的 200ms。查询分支取消不影响同级的其他操作;入口取消则会向这些派生分支传播。这里的数字只是预算示例,实际超时要结合接口总预算和下游耗时设置。

创建了可取消子 Context 的函数,要在该作用域工作结束时调用返回的 cancel,通常紧接创建后安排 defer cancel()。即便设置了超时,也应及时取消,以释放父子关联和定时器等资源。普通函数返回本身不会自动取消它创建的 Context。

调用链已有 ctx 时,应继续传它;中途随手换成 Background 会切断原请求的取消和截止时间。Background 适合创建根作用域,TODO 用于暂时还不确定来源的情况,不应传 nil。

底层为什么能逐级传播

Context 是接口,包含 Deadline、Done、Err、Value 四个方法:分别提供截止时间、取消通知通道、取消原因和请求级值。取消前 Err 为 nil;取消后通常是 context.Canceled 或 context.DeadlineExceeded。

以 Go 1.27.2 标准库为例,常见派生实现各有职责:

  • cancelCtx 保存父 Context、取消状态和子级关联。取消时关闭 Done 通道,并继续取消关联的子级。多个监听者都能观察到通道关闭,因此可以广播通知。
  • timerCtx 在可取消上下文上增加截止时间和定时器,到期触发取消;提前取消时也会停止相关定时器。
  • valueCtx 保存父 Context 与一组键值。查找时先看当前层,不匹配再沿父链查找;不是每次派生都复制一份全量 Map。子级添加同名键会遮蔽上层值,不会修改父级。

传播也不意味着每创建一个子 Context 就启动一个 goroutine。标准库能识别的可取消父级通常通过子级集合关联;其他实现可能采用回调或监听 goroutine 等路径。

使用时还要注意什么

WithValue 适合 Trace ID 等跨调用边界的请求级信息,普通业务参数、可选配置和返回值应通过明确的参数、返回值或 channel 传递。键应使用包内自定义的可比较类型,避免不同包使用同一个字符串键发生碰撞。Context 本身可被多个 goroutine 并发使用,但放进去的 Map、指针等对象仍需要自己的并发保护。

Context 对象也不会自动跨网络传过去。HTTP 或 RPC 调用需要客户端、服务端或框架按协议传递选定的追踪信息和截止时间,并把取消与具体调用连接起来,不能假设所有 Value 都会被序列化。

如果任务一直执行计算、阻塞在不支持 Context 的操作中,或者根本不检查取消,它仍可能继续运行。需要确认任务已经结束时,还要配合 WaitGroup 等等待机制;取消也不等于回滚已经发生的数据库写入或外部操作。

参考资料

相关面经

3 篇

百度

Go 后端开发工程师
二面
查看原面经 →
Go 里的 Context 是做什么的?你怎么理解?

哔哩哔哩(B站)

Agent 开发工程师
社招一面
查看原面经 →
go的context有什么用,多级传递的实现

浦发银行

AI 开发
社招一面
查看原面经 →
Go的context底层原理

相关题目

4 题