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 ...
随机推荐
- Mapper that could not be found
现象1 mapper 资源扫不到 resources 建的是 目录 ,不是 package 所以如果直接 a.b 的方式创建,会扫描不到 mapper.xml 文件 现象2 缺少配置文件 HisDru ...
- FTP 被动模式配置
总结:FTP 21端口,可以主动连接,防火墙配置一下21端口放行就OK了.非21端口,需要设成被动连接和端口范围.防火墙要做相应的配置 原理 https://www.cnblogs.com/zjoch ...
- SpringBoot Docker Skywalking agent 不生效
SpringBoot Skywalking agent 通过 Dockfile 配置 不生效 ENTRYPOINT ["java","-Djava.security.eg ...
- Rocketmq学习2——Rocketmq消息过滤&事务消息&延迟消息原理源码浅析
系列文章目录和关于我 零丶引入 在<Rocketmq学习1--Rocketmq架构&消息存储&刷盘机制>中我们学习了rocketmq的架构,以及消息存储设计,在此消息存储设 ...
- 最被低估的Python绘图库!Matlplotlib 超强实力鉴赏
最被低估的Python绘图库!Matlplotlib 超强实力鉴赏 Matplotlib Matplotlib 是一个 Python 的 2D绘图库,它以各种硬拷贝格式和跨平台的交互式环境生成出版质量 ...
- freeswitch的3XX重定向
概述 sip协议标准RFC3261中,对3XX重定向有明确的定义. freeswitch中如何使用3XX redirect的特性,如何落地,应用场景有哪些? 环境 centos:CentOS rel ...
- C#树的实现
ddd /// <summary> /// 遍历,线索化等操作的接口 /// </summary> interface ITravelBinTree { void PreOrd ...
- 解决Xshell/Xftp提示“要继续使用此程序必须应用到最新的更新或者新版本”(临时规避和彻底解决方案)
一.xshell与xftp登录时提示,但是更新却又每次都失败,无法登录 二. 临时规避方案:手动修改日期为1年前,问题解决软件可以打开,但是每次启动都要手动修改,甚是麻烦 三.彻底解决方案,修改xs ...
- linux 对子用户配置java 环境变量
转载请注明出处: 若服务器安装 jdk 时用的是root 用户,则root 用户登录服务器可以直接获取Java环境. 当切换到其他子用户时,则会发现环境不存在,命令不存在等. 解决方案: 1. 先切换 ...
- ElasticSearch使用实践(文档操作)
可以使用Docker安装ES和Kibana: 使用docker-compose安装ElasticSearch和Kibana: version: '3.1' services: elasticsearc ...
