golang: 模仿 VictoriaMetrics 中的做法,通过把局部变量放在自定义 Context 对象中来做到hot path 的 0 alloc
作者:张富春(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) // 业务逻辑函数
}
golang: 模仿 VictoriaMetrics 中的做法,通过把局部变量放在自定义 Context 对象中来做到hot path 的 0 alloc的更多相关文章
- .NET中利用反射来实现自动映射两个对象中的数据成员
在以前的项目开发之中,经常会遇到这样一个问题:比如在外面项目的架构设计之中,我们采用MVC和EntityFramework来构建一个Web应用程序.比如我们采用常用的多层架构,例如有Presentat ...
- CSS中2d转换:transition过渡放在:hover伪类中与应用在整个元素中区别
css的2d转换十分强大,能够在不使用js的情况下,实现页面的元素与用户之间更多动态的交互,增强用户体验.其中使用最多的就是hover伪类. 1.创建一个页面的div元素: <!DOCTYPE ...
- JavaScript中的内置对象-8--4.date对象中-获取,设置日期时间的方法; 获取,设置年月日时分秒及星期的方法;
学习目标 1.掌握创建日期对象的方法 2.掌握date对象中获取日期时间的方法 3.掌握date对象中设置日期时间的方法 如何创建一个日期对象 语法:new Date(); 功能:创建一个日期时间对象 ...
- Flexigrid从对象中加载数据
(有问题,在找…………) Flexigrid是用来动态加载数据的一种比较好(老)的Jquery表插件,然后有些时候,我们需要其从本地或者jQuery对象中加载数据,比如有这么个需求,页面显示中有两个表 ...
- JavaScript之面向对象学习二(原型属性对象与in操作符)获取对象中所有属性的方法
1.原型属性对象于in操作符之in单独使用 有两种方式使用in操作符:单独使用和在for-in循环中使用.在单独使用中,代码如下: function Person(){ } Person.protot ...
- c++ , const对象中的变量不能被修改
const对象中的变量不能被修改,即使const对象中的函数也不能修改该对象中的变量值 #include <iostream> using namespace std; //------- ...
- 设计模式系列之迭代器模式(Iterator Pattern)——遍历聚合对象中的元素
模式概述 模式定义 模式结构图 模式伪代码 模式改进 模式应用 模式在JDK中的应用 模式在开源项目中的应用 模式总结 说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修 ...
- 使用 history 对象和 location 对象中的属性和方法制作一个简易的网页浏览工具
查看本章节 查看作业目录 需求说明: 使用 history 对象和 location 对象中的属性和方法制作一个简易的网页浏览工具 实现思路: 使用history对象中的 forward() 方法和 ...
- ios怎样实现快速将显卡中数据读出压缩成视频在cocos2dx扩展开发中
如果解决ios怎样实现快速将显卡中数据读出压缩成视频在cocos2dx扩展开发中 手机平台性能是个关键问题. 压缩视频分成3个步骤: 读取显卡数据, 使用编码器压缩,保存文件. 使用libav 压缩的 ...
- js中如何以最简单的方式将数组元素添加到对象中
//如题,通常做法就是循环数组,最后在添加length属性,如: var obj = {}; var pushArr = [11,22,33,44,55,66]; for(var i=0;i<p ...
随机推荐
- 如何在跨平台的环境中创建可以跨平台的后台服务,它就是 Worker Service。
一.简介 最近,有一个项目要使用 Windows 服务,来做为一个软件项目的载体.我想了想,都已经到了跨平台的时代了,会不会有替换 Windows 服务的技术出现呢?于是,在网络上疯狂的搜索了一番,真 ...
- Solon2 之基础:四、应用启动过程与完整生命周期
串行的处理过程(含六个事件扩展点 + 两个函数扩展点),代码直接.没有什么模式.易明 提醒: 启动过程完成后,项目才能正常运行(启动过程中,不能把线程卡死了) AppBeanLoadEndEvent ...
- Linux 查找进程所在目录
查找进程所在目录位置 # 打出进程ID [root@iZuf64tp28136djioi3ki8Z /]# ps -ef|grep redis root 3451 1 0 Jun10 ? 07:02: ...
- matplotlib 图表生成
条形颜色演示 import matplotlib.pyplot as plt ''' 将plt.subplots()函数的返回值赋值给fig和ax俩个变量 plt.subplots()是一个函数,返回 ...
- 使用 DPO 微调 Llama 2
简介 基于人类反馈的强化学习 (Reinforcement Learning from Human Feedback,RLHF) 事实上已成为 GPT-4 或 Claude 等 LLM 训练的最后一步 ...
- #3038:How Many Answers Are Wrong (带权并查集)
HDU 3038 第一次接触带权并查集 //带权并查集 更新父节点的同时更新权值 #include<bits/stdc++.h> using namespace std; const in ...
- 『NexT』,一款 NexT 风格的 Typora 主题
很喜欢 Hexo 中的 Next 主题,便想要在 Typora 中书写时获得和在 Hexo 中一样的预览效果,翻了一下Typora的theme仓库发现已经有dalao (知乎@Bill Chen)写了 ...
- 五、java操作redis
系列导航 一.redis单例安装(linux) 二.redis主从环境搭建 三.redis集群搭建 四.redis增加密码验证 五.java操作redis --demo主方法 package com. ...
- md文件的基本常用编写语法
md简介 .md即markdown文件的基本常用编写语法,是一种快速标记.快速排版语言,现在很多前段项目中的说明文件readme等都是用.md文件编写的,而且很多企业也在在鼓励使用这种编辑方式.下面就 ...
- 人人都会Kubernetes(二):使用KRM实现快速部署服务,并且通过域名发布
1. 上节回顾 上一小节<人人都会Kubernetes(一):告别手写K8s yaml,运维效率提升500%>介绍了KRM的一些常用功能,并且使用KRM的DEMO环境,无需安装就可以很方便 ...
