golang: 模仿 VictoriaMetrics 中的做法,通过把局部变量放在自定义 Context 对象中来做到hot path 的 0 alloc
  ZvAhkxhPQwyp 2023年11月02日 27 0
Go

作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!


使用 benchmark 压测过程中通常会出现这样的信息:

go test -v -bench=. -benchmem
f1     10000        120860 ns/op        2433 B/op         28 allocs/op
f2     10000        120288 ns/op        2288 B/op         26 allocs/op

可以看见 f1 在每次运行都产生了 28 次内存分配。
gc 通常是 golang 最大的性能杀手,减少内存分配对性能提升非常明显。

可以把程序区分为 hot path非hot path,hot path 即运行最频繁,消耗时间最多的程序执行路径。VictoriaMetrics 的作者 Valyala 建议在 Hot path 上做到 0 alloc.

然而,必须需要在函数间传递的对象指针,必然需要引起 alloc。减少内存分配的一个办法是 sync.Pool,但是如果在 A 函数中使用 sync.Pool.Get, 而在 B 函数中使用 sync.Pool.Put,这样的程序流程比较混乱,不容易维护。且,当存在大量的不同对象时,其 sync.Pool 的种类也很多;sync.Pool 还有全局锁,会影响程序的并发性。

VictoriaMetrics 中大量的使用了这样的技巧:

1. 定义自己的 Context 对象

type MyContext struct{

}

// 业务函数的第一个参数都是 MyContext
func BizFunc1(ctx *MyContext){}

func BizFunc2(ctx *MyContext){}

2. 所有在函数间传递的变量(引起栈逃逸的),都定义在 MyContext 中

type MyContext struct{
     tempBuffer []byte
}

//  如果函数都依赖 tempBuffer, 把局部变量定义到 MyContext 中
func BizFunc1(ctx *MyContext){
     ctx.tempBuffer = append(ctx.tempBuffer, "str1"...)
}

func BizFunc2(ctx *MyContext){
    ctx.tempBuffer = append(ctx.tempBuffer, "str2"...)
}

3. MyContext 本身从 sync.Pool 中获取

var poolOfMyContext = sync.Pool{
    New: func() interface{}{
        return &MyContext{}
    }
}

// 业务入口函数
func BizEntrance(){
    ctx := poolOfMyContext.Get().(*MyContext)
    defer poolOfMyContext.Put(ctx)
    //
    callBizFunc(ctx)  // 业务逻辑函数
}

4. MyContext 对象提供 Reset() 方法

对分配好的各种缓冲区重用,避免反复分配。

func (c *MyContext) Reset() {
     c.tempBuffer = c.tempBuffer[:0]  // 重用分配好的空间
}

// 业务入口函数
func BizEntrance(){
    ctx := poolOfMyContext.Get().(*MyContext)
    ctx.Reset()  // 需要清空内容,避免上次的数据干扰运行结果
    defer poolOfMyContext.Put(ctx)
    //
    callBizFunc(ctx)  // 业务逻辑函数
}
【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  uGYzDadp0Cs7   2024年04月18日   58   0   0 Go
  hyrB1Ag4eVs8   2024年04月15日   38   0   0 Go
  YFCZjJLTjJgW   17天前   21   0   0 Go
  uGYzDadp0Cs7   2024年04月16日   94   0   0 Go
ZvAhkxhPQwyp