go 复制context


写在前面

在项目中有时候需要异步运行某个函数,但是又不能因为主程序退出了而提前终止。比如一个异步接口触发的某个耗时任务,接口之间一般都会设有超时时间。所以不能因为接口已经结束了而导致异步任务终止,但是又不能传空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


文章作者: Alex
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Alex !
  目录