context详解

context详解

简介

context.Context是go的标准库,主要用于跨goroutine传递取消信号、截止时间(超时)、以及在请求生命周期内传递数据。可以用来设置截止日期、同步信号、传递请求相关值的结构体,与goroutine有比较密切的关系。

在web程序中,每个request都需要开启一个goroutine做一些事情,这些goroutine有可能会开启其他的goroutine去访问后端资源,比如数据库、rpc服务器等,他们需要访问一些共享的资源,比如用户身份信息、认证token、请求截止时间等,这时候可以通过Context,来跟踪这些goroutine,并且通过Context来控制它们,这就是go提供的Context,称为上下文

context主要是用来做并发控制的。

  • 程序中使用方式

在服务入口创建context上下文,并不断透传下去。

context被当做第一个参数(官网建议),并且不断透传下去。

Context定义

type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
    Value(key interface{}) interface()
}

Deadline

Deadline方法是获取设置的截止时间的意思,第一个返回值是截止时间,到了这个时间点,Context会自动发起取消请求,第二个返回值ok===false时表示没有设置截止时间,如果需要取消的话,需要调用取消函数进行取消。

Done

Done方法返回一个只读的chan,类型为struct{},在goroutine中,如果该方法返回的chan可以读取,则意味着parent context已经发起取消请求,通过Done方法收到这个信号后,就应该清理操作,然后退出goroutine,之后,Err方法会返回一个错误,告知为什么Context被取消。

Err

Err方法返回取消的错误原因。为什么Context被取消。

Value

Value方法获取该Context上绑定的值,是一个键值对,通过一个Key才可以获取对应的值,这个值一般是线程安全的。

创建context

context包主要提供两种方式创建context

  • context.Backgroud()
    • 上下文的默认值,其他所有的上下文都应该从它衍生(Derived)出来。
  • context.TODO()
    • 只在不确定应该使用哪种上下文时使用。

大多数情况下,我们都使用context.Backgroud作为起始的上下文向下传递。上述两种方式创建的是根context,不具备任何功能。

具体功能使用context包提供的With系列函数进行派生:

func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{}) Context

WithValue携带数据

创建携带treace_id的ctx,在程序中传递,从中派生的任何context都会获取此值。

注意事项:

不建议使用context传递关键参数,关键参数应该显示声明出来,不应该隐式处理,context最好是携带签名、treace_id这类值。

超时控制

通常健壮的程序都要设置超时间,避免因为服务端长时间响应消耗资源,所以一些web框架或rpc框架都会采用withTimeout或withDeadline来做超时控制,当一次请求到达我们设置的超时时间,就会及时取消,不再往下执行。

withTimeout或withDeadline都会返回一个cancelFunc方法,通过调用这个方法可以提前进行取消。

WithCancel取消控制

日常业务开发中,我们往往为了完成一个复杂的需求会开多个goroutine去完成一些工作,这就可能导致我们在一次请求中开了多个goroutine却无法控制它们,这时我们就可以使用withCancel来衍生一个context传递到不同的goroutine中,当我们想让这些goroutine停止运行,就可以调用cancel来进行取消。

总结

go语言中的context.Context的主要作用还是在多个goroutine组成的树中同步取消信号以减少对资源的消耗和占用。

虽然它有传值的功能,但是这个功能很少用到,在真正使用传值的功能也应该非常谨慎,使用context.Context进行传参请求是一种非常差的设计。

比较常见的使用场景是:传递请求对应用户的认证令牌分布式追踪的请求ID

posted @ 2025-08-09 14:39  biby  阅读(37)  评论(0)    收藏  举报