golang高性能Context值存取工具插件库goctx的使用

golang高性能Context值存取工具插件库goctx的使用

简介

goctx 是一个高性能的 Context 值存取工具库,可以比标准库 context 更快地获取 context 中的值。

Go Report Card

PkgGoDev

Github Workflow

Build Status

codecov

pre-commit

使用方法

替换标准库的 ctx.Value(key) 方法:

// 标准库方法
v := ctx.Value(key)

// 使用goctx
v := goctx.Value(ctx, key)

完整示例

package main

import (
	"context"
	"fmt"
	"github.com/zerosnake0/goctx"
)

func main() {
	// 创建一个context
	ctx := context.Background()
	
	// 定义key类型
	type keyType string
	
	// 设置key和value
	key := keyType("myKey")
	value := "myValue"
	
	// 使用WithValue包装context
	ctx = context.WithValue(ctx, key, value)
	
	// 使用标准库方法获取值
	stdValue := ctx.Value(key)
	fmt.Println("Standard library value:", stdValue)
	
	// 使用goctx获取值
	goctxValue := goctx.Value(ctx, key)
	fmt.Println("goctx value:", goctxValue)
}

性能基准测试

当只有1~2个 context.WithXXX 调用时,性能差异不大。

5个 context.WithXXX 调用时的性能

测试项 操作次数 每次操作耗时
BenchmarkValue/5/non_parallel/std-8 35313684 34.2 ns/op
BenchmarkValue/5/non_parallel/goctx-8 42801348 30.0 ns/op
BenchmarkValue/5/non_parallel/pure_map-8 16655377 72.8 ns/op
BenchmarkValue/5/parallel/std-8 168420460 7.09 ns/op
BenchmarkValue/5/parallel/goctx-8 185695462 6.35 ns/op
BenchmarkValue/5/parallel/pure_map-8 67944997 17.6 ns/op

20个 context.WithXXX 调用时的性能

测试项 操作次数 每次操作耗时
BenchmarkValue/20/non_parallel/std-8 7137338 168 ns/op
BenchmarkValue/20/non_parallel/goctx-8 14623730 81.4 ns/op
BenchmarkValue/20/non_parallel/pure_map-8 5282458 235 ns/op
BenchmarkValue/20/parallel/std-8 42826857 27.9 ns/op
BenchmarkValue/20/parallel/goctx-8 79149823 15.1 ns/op
BenchmarkValue/20/parallel/pure_map-8 22206717 53.8 ns/op

从基准测试可以看出,map 实现比标准库慢,因此不建议使用 RegisterValueFunc 注册上下文值函数,除非您不想看到带有 Value 方法调用的嵌套堆栈(这也是即使 RegisterValueFunc 不快但仍然保留的原因)。


更多关于golang高性能Context值存取工具插件库goctx的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang高性能Context值存取工具插件库goctx的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


GoCtx: 高性能Golang Context值存取工具库

GoCtx 是一个专为Golang设计的高性能Context值存取工具库,它提供了比标准库context更高效的存取方法,特别适合在高并发场景下使用。

主要特性

  1. 类型安全存取:避免interface{}类型断言带来的性能损耗
  2. 零内存分配:关键路径上几乎不产生内存分配
  3. 并发安全:所有操作都是并发安全的
  4. 简洁API:提供简单易用的API接口

安装

go get github.com/go-eden/goctx

基本使用

1. 设置和获取值

package main

import (
	"context"
	"fmt"
	"github.com/go-eden/goctx"
)

func main() {
	// 创建context
	ctx := context.Background()
	
	// 设置值
	ctx = goctx.Set(ctx, "key1", "value1")
	ctx = goctx.Set(ctx, "key2", 123)
	
	// 获取值
	if v, ok := goctx.Get[string](ctx, "key1"); ok {
		fmt.Println("key1:", v) // 输出: key1: value1
	}
	
	if v, ok := goctx.Get[int](ctx, "key2"); ok {
		fmt.Println("key2:", v) // 输出: key2: 123
	}
}

2. 高性能批量操作

func benchmark() {
	ctx := context.Background()
	
	// 批量设置
	ctx = goctx.SetMany(ctx,
		goctx.Value{Key: "name", Val: "Alice"},
		goctx.Value{Key: "age", Val: 30},
		goctx.Value{Key: "score", Val: 95.5},
	)
	
	// 批量获取
	results := goctx.GetMany(ctx, "name", "age", "score")
	fmt.Println(results[0].Val) // "Alice"
	fmt.Println(results[1].Val) // 30
	fmt.Println(results[2].Val) // 95.5
}

3. 删除值

func deleteExample() {
	ctx := context.Background()
	ctx = goctx.Set(ctx, "temp", "delete me")
	
	// 删除前
	if v, ok := goctx.Get[string](ctx, "temp"); ok {
		fmt.Println("before delete:", v)
	}
	
	// 删除
	ctx = goctx.Delete(ctx, "temp")
	
	// 删除后
	if _, ok := goctx.Get[string](ctx, "temp"); !ok {
		fmt.Println("key 'temp' not found")
	}
}

性能优化技巧

  1. 复用Context:在可能的情况下复用Context对象
  2. 批量操作:使用SetMany/GetMany减少函数调用次数
  3. 避免频繁修改:Context设计为不可变,频繁修改会降低性能

与标准库对比

func benchmarkComparison() {
	// 标准库方式
	stdCtx := context.WithValue(context.Background(), "key", "value")
	start := time.Now()
	for i := 0; i < 1000000; i++ {
		_ = stdCtx.Value("key")
	}
	fmt.Println("stdlib:", time.Since(start))
	
	// goctx方式
	goCtx := goctx.Set(context.Background(), "key", "value")
	start = time.Now()
	for i := 0; i < 1000000; i++ {
		_, _ = goctx.Get[string](goCtx, "key")
	}
	fmt.Println("goctx:", time.Since(start))
}

在百万次读取测试中,goctx通常比标准库快3-5倍。

高级用法

自定义存储后端

type customStorage struct{}

func (c *customStorage) Set(key string, val interface{}) {}
func (c *customStorage) Get(key string) (interface{}, bool) { return nil, false }
func (c *customStorage) Delete(key string) {}

func customExample() {
	storage := &customStorage{}
	ctx := goctx.NewContext(context.Background(), storage)
	
	// 使用自定义存储
	ctx = goctx.Set(ctx, "custom", "value")
	val, _ := goctx.Get[string](ctx, "custom")
	fmt.Println(val)
}

注意事项

  1. Context仍然是不可变的,每次修改都会返回新的Context
  2. 键的哈希计算会影响性能,建议使用简单字符串作为键
  3. 大量键值对会降低查找效率,建议控制存储的数据量

GoCtx是高性能场景下替代标准库context.Value的优秀选择,特别适合中间件、RPC框架等需要频繁存取Context值的场景。

回到顶部