作者:張富春(ahfuzhang),轉(zhuǎn)載時(shí)請(qǐng)注明作者和引用鏈接,謝謝!
- cnblogs博客
- zhihu
- Github
-
公眾號(hào):一本正經(jīng)的瞎扯
使用 benchmark 壓測(cè)過(guò)程中通常會(huì)出現(xiàn)這樣的信息:
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
可以看見(jiàn) f1 在每次運(yùn)行都產(chǎn)生了 28 次內(nèi)存分配。
gc 通常是 golang 最大的性能殺手,減少內(nèi)存分配對(duì)性能提升非常明顯。
可以把程序區(qū)分為 hot path
和 非hot path
,hot path 即運(yùn)行最頻繁,消耗時(shí)間最多的程序執(zhí)行路徑。VictoriaMetrics 的作者 Valyala 建議在 Hot path 上做到 0 alloc.
然而,必須需要在函數(shù)間傳遞的對(duì)象指針,必然需要引起 alloc。減少內(nèi)存分配的一個(gè)辦法是 sync.Pool,但是如果在 A 函數(shù)中使用 sync.Pool.Get, 而在 B 函數(shù)中使用 sync.Pool.Put,這樣的程序流程比較混亂,不容易維護(hù)。且,當(dāng)存在大量的不同對(duì)象時(shí),其 sync.Pool 的種類(lèi)也很多;sync.Pool 還有全局鎖,會(huì)影響程序的并發(fā)性。
VictoriaMetrics 中大量的使用了這樣的技巧:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-582418.html
1. 定義自己的 Context 對(duì)象
type MyContext struct{
}
// 業(yè)務(wù)函數(shù)的第一個(gè)參數(shù)都是 MyContext
func BizFunc1(ctx *MyContext){}
func BizFunc2(ctx *MyContext){}
2. 所有在函數(shù)間傳遞的變量(引起棧逃逸的),都定義在 MyContext 中
type MyContext struct{
tempBuffer []byte
}
// 如果函數(shù)都依賴(lài) 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{}
}
}
// 業(yè)務(wù)入口函數(shù)
func BizEntrance(){
ctx := poolOfMyContext.Get().(*MyContext)
defer poolOfMyContext.Put(ctx)
//
callBizFunc(ctx) // 業(yè)務(wù)邏輯函數(shù)
}
4. MyContext 對(duì)象提供 Reset() 方法
對(duì)分配好的各種緩沖區(qū)重用,避免反復(fù)分配。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-582418.html
func (c *MyContext) Reset() {
c.tempBuffer = c.tempBuffer[:0] // 重用分配好的空間
}
// 業(yè)務(wù)入口函數(shù)
func BizEntrance(){
ctx := poolOfMyContext.Get().(*MyContext)
ctx.Reset() // 需要清空內(nèi)容,避免上次的數(shù)據(jù)干擾運(yùn)行結(jié)果
defer poolOfMyContext.Put(ctx)
//
callBizFunc(ctx) // 業(yè)務(wù)邏輯函數(shù)
}
到了這里,關(guān)于golang: 模仿 VictoriaMetrics 中的做法,通過(guò)把局部變量放在自定義 Context 對(duì)象中來(lái)做到hot path 的 0 alloc的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!