go context 特性

前言

​ 关于 context 的源码分析网上已经有很多优秀的文章了,本文主要记录一下 context 的使用注意事项和技巧,还有 context 为什是并发安全的。

context 使用注意事项

资源未释放

 	ctx, _ := context.WithTimeout(context.TODO(), 1*time.Second)

​ 在编写代码的过程当我们申请了一个资源应该养成释放这个资源的习惯,相比 c++ 语言在析构函数里面释放资源,Go 通常是借助 defer 语义

 	ctx, cancel := context.WithTimeout(context.TODO(), 1*time.Second)
 	defer cancel()

context value 被覆盖

​ 我们通常使用以下语法,使用字符串 key 设置 context value,在多人维护一个项目或者调用其他函数的时候有可能因为定义了同样的 key 导致 value 被覆盖,从而产生意想不到的问题

ctx = context.WithValue(ctx, "key", "value")

参照 context 包我们可以发现,他是通过自定义类型避免参数被覆盖问题,代码如下,在设置 value 的时候自定义了一个 cancelCtxKey 类型

var cancelCtxKey int

p, ok := parent.Value(&cancelCtxKey).(*cancelCtx)
if !ok {
	return nil, false
}
并发安全特性

​ context 是并发安全的,当 ctx 在多个协程之间传播并进行 WithValue 时是怎么保证并发安全的呢,答案是 COW(写时复制),接下来我们看一下 WithValue 实现的源码

func WithValue(parent Context, key, val any) Context {
	if parent == nil {
		panic("cannot create context from nil parent")
	}
	if key == nil {
		panic("nil key")
	}
	if !reflectlite.TypeOf(key).Comparable() {
		panic("key is not comparable")
	}
	return &valueCtx{parent, key, val}
}

​ 从源码可以发现在使用 WithValue 时 重新 new 了一个 valueCtx 对象,因此在不同的协程里面使用的是不同的副本,所以就不会有并发问题,有点 MVCC 的味道了。

Githubwang1309

Reference
  1. Package Golang Context
  2. Wikipedia COW
  3. Wikipedia MVCC
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值