Golang的context理解

使用方法

context用于表示一个请求的上下文。一个网络请求,一般开启一个协程处理,而这个协程内部还会开启其它的协程继续处理。为了传递一个请求在不同协程中的处理情况(比如是否超时等),我们利用context来记录这个情况。同样的,对于一些IO处理,也需要context保存状态,比如超时时间等。

context一般用以下两种方式传递:

  • 作为函数调用的第一个参数
  • 作为一个请求结构体的可选配置
func (d *Dialer) DialContext(ctx context.Context, network, address string) (Conn, error){}
func (r *Request) WithContext(ctx context.Context) *Request

context应该在程序中流动,而不应该存储,不要直接存储context在结构体中等。一般来说,一个请求的contextmain中使用context.BackGorund()方法生成。一般来说,这个用于控制超时时间。

context可以继承,一旦一个context取消了,那么继承自该context的所有context都会取消,但是不会影响它的父context

context可以携带一些值,比如:

func WithValue(parent Context, key, val interface{}) Contex

key必须是可比较的,而且不要是内嵌类型,自定义类型,比如:

一般来说,context携带的值应该是request-scoped类型的,即仅仅是本次请求范围内会用到的。像数据库字段之类的,不要在这里写入,因为这是全局都用的。使用context方式传递数据,会造成函数参数意义不明的情况,给出对比:

// 参数意义不明确
func IsAdminUser(ctx context.Context) bool {
    x := token.GetToken(ctx)
    userObject := auth.AuthenticateToken(x)
    return userObject.IsAdmin() || userObject.IsRoot()
}

// 明确参数的意义,这是合理的方式
func IsAdminUser(token string, authService AuthService) int {
    userObject := authService.AuthenticateToken(token)
    return userObject.IsAdmin() || userObject.IsRoot()
}

但是,有些情况下,可以简化API的设计。比如我们有一个较长的函数调用链,向userId这种数据,却要从头到尾传递整个调用链,这不是一个好的方法。我们此时可以把这些数据封装到context中。这些数据不能是控制类型的字段,即传入函数的执行结果,最好不要依赖这些值;但是log等函数,可以打印这些数据,因为这部影响函数执行结果。

一般不建议使用context.Value的模式,这在后期重构等时候,造成一些不好的影响,除非必要,否则勿用。

使用原则和技巧

  • 不要把Context放在结构体中,要以参数的方式传递,parent Context一般为Background
  • 应该要把Context作为第一个参数传递给入口请求和出口请求链路上的每一个函数,放在第一位,变量名建议都统一,如ctx。
  • 给一个函数方法传递Context的时候,不要传递nil,否则在tarce追踪的时候,就会断了连接
  • Context的Value相关方法应该传递必须的数据,不要什么数据都使用这个传递
  • Context是线程安全的,可以放心的在多个goroutine中传递
  • 可以把一个 Context 对象传递给任意个数的 gorotuine,对它执行取消操作时,所有 goroutine 都会接收到取消信号。

参考资料:

  • https://blog.golang.org/context
  • https://juejin.im/post/5a6873fef265da3e317e55b6
  • https://www.ardanlabs.com/blog/2019/09/context-package-semantics-in-go.html
  • http://p.agnihotry.com/post/understanding_the_context_package_in_golang/
  • https://medium.com/@cep21/how-to-correctly-use-context-context-in-go-1-7-8f2c0fafdf39
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值