写在前面
在项目中有时候需要异步运行某个函数,但是又不能因为主程序退出了而提前终止。比如一个异步接口触发的某个耗时任务,接口之间一般都会设有超时时间。所以不能因为接口已经结束了而导致异步任务终止,但是又不能传空context到异步任务中,因为还需要用到ctx中的k,v。
基于这个前提,想写一个复制context中k,v而去掉cancel的方法。
代码
package common
import (
"context"
"reflect"
"unsafe"
)
type iface struct {
itab, data uintptr
}
type valueCtx struct {
context.Context
key, value any
}
// CopyContext. copy context
func CopyContext(ctx context.Context) context.Context {
newCtx := context.Background()
kv := make(map[any]any)
getKeyValues(ctx, kv)
for k, v := range kv {
newCtx = context.WithValue(newCtx, k, v)
}
return newCtx
}
func getKeyValues(ctx context.Context, kv map[any]any) {
rtType := reflect.TypeOf(ctx).String()
// 遍历到最底层,返回
if rtType == "*context.emptyCtx" {
return
}
ictx := *(*iface)(unsafe.Pointer(&ctx))
if ictx.data == 0 {
return
}
valCtx := (*valueCtx)(unsafe.Pointer(ictx.data))
if valCtx != nil && valCtx.key != nil && valCtx.value != nil {
kv[valCtx.key] = valCtx.value
}
getKeyValues(valCtx.Context, kv)
}
结束语
这段代码挺简单的,不详细介绍,需要的可以复制过去。
参考
[1]go context 拷贝去除 cancel 函数
[2]https://github.com/ZBIGBEAR/copyctx