Go语言基准测试(benchmark)三部曲之二:内存篇

news2024/11/23 21:47:13

欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

本篇概览

  • 本文是《Go语言基准测试(benchmark)三部曲》的第二篇,目标是掌握如何用基准测试来观察被测方法的内存分配情况
  • 今天除了常规的操作,即指定参数增加内存相关的测试结果,咱们还要针对内存分配问题增加几个方法用于对比验证,最终达到根据基准测试发现内存问题的目标

基本操作

  • 查看方法中的内存使用情况,请在原来的benchmark测试命令中增加-benchmem参数,完整命令如下,用的是前文的BenchmarkFib和BenchmarkParallelFib方法做基准测试
go test -bench='Fib$' -benchmem .
  • 测试结果如下,竟然没有使用内存,不过想想也是,fib方法主要是斐波那契数列计算,未涉及到内存分配,看来这个例子不具有说明性,咱们需要写两个涉及到内存分配的方法,再对他们做基准测试看看效果
    在这里插入图片描述

新增两个方法用于基准测试

  • 为了展现内存分配的不同程度影响,这里会编写两个方法用于对比测试
  • 这两个方法的功能是一样的:产生N个随机数(N是方法的入参),然后放入切片中
  • 虽然功能一样,但是这两个方法最大的不同就是:名为newSlice的方法,创建切片的时候没有指定切片容量,另一个名为newSliceWithCap的方法在创建切片的时候指定了切片容量
  • newSlice和newSliceWithCap方法的源码如下,都在main.go中
// 往切片中放入指定数量的随机数,这个切片没有提前设置容量
func newSlice(n int) []int {
	rand.Seed(time.Now().UnixNano())

	// 注意,这里在生成切片的时候并没有指定容量
	nums := make([]int, 0)

	for i := 0; i < n; i++ {
		nums = append(nums, rand.Int())
	}

	return nums
}

// 往切片中放入指定数量的随机数,这个切片提前设置了容量
func newSliceWithCap(n int) []int {
	rand.Seed(time.Now().UnixNano())

	// 注意,这里在生成切片的时候指定了容量
	nums := make([]int, 0, n)

	for i := 0; i < n; i++ {
		nums = append(nums, rand.Int())
	}

	return nums
}
  • 接下来在main_test.go文件中增加基准测试的代码,先准备三个常量,后面会用到
const (
	SLICE_LENGTH_MILLION         = 1000000   // 往切片中添加数据的长度,百万
	SLICE_LENGTH_TEN_MILLION     = 10000000  // 往切片中添加数据的长度,千万
	SLICE_LENGTH_HUNDRED_MILLION = 100000000 // 往切片中添加数据的长度,亿
)
  • 然后是两个基准测试的方法,分别用于测试newSlicenewSliceWithCap
func BenchmarkNewSlice(b *testing.B) {
	for n := 0; n < b.N; n++ {
		newSlice(SLICE_LENGTH_MILLION)
	}
}

func BenchmarkNewSliceWithCap(b *testing.B) {
	for n := 0; n < b.N; n++ {
		newSliceWithCap(SLICE_LENGTH_MILLION)
	}
}
  • 代码写完了,从理论上分析,切片未指定容量,就会随着内容的增加发生新的内存分配,因此newSlice的内存使用和内存分配都应该超过newSliceWithCap,咱们来测试一下,看数据和推论是否匹配
  • 执行以下命令,正则表达式的意思是只执行BenchmarkNewSliceBenchmarkNewSliceWithCap这两个方法
go test -bench='BenchmarkNewSlice$|BenchmarkNewSliceWithCap$' -benchmem .
  • 结果如下,可见未指定容量的切片在保存数据时会触发扩容,会分配更多内存,内存分配次数也会跟多,每次方法执行的耗时也更多,而提前指定了容量的切片,中途不再发生扩容,内存分配量更小,方法执行耗时也更少(对我们的开发还是有指导意义的)
go test -bench='BenchmarkNewSlice$|BenchmarkNewSliceWithCap$' -benchmem .
goos: darwin
goarch: arm64
pkg: benchmark-demo
BenchmarkNewSlice-8          68  16568869 ns/op 41678153 B/op  38 allocs/op
BenchmarkNewSliceWithCap-8   84  14098503 ns/op  8003589 B/op   1 allocs/op
PASS
ok      benchmark-demo  2.769s

同一方法的不同数量级对比

  • 经过前面的测试,可以确定newSliceWithCap方法由于未指定切片容量,在保存数据的中途会触发扩容,从而导致内存分配的大小和次数都会增加
  • 这个结果是对比newSlice方法得出的,此方法指定了切片容量的,接下里咱们换种测试方式:让newSliceWithCap内的切片分别存入不同数量级的数据,观察此方法在面对这些数据时的内存分配情况
  • 在main_test.go中增加一个方法
func testNewSlice(len int, b *testing.B) {
	for n := 0; n < b.N; n++ {
		newSlice(len)
	}
}
  • 现在只要新增多个BenchmarkXXX方法,每个方法都调用testNewSlice并传入不同数量级的数字,就能实现对比测试了,详细代码如下,咱们分解测试百万、千万、亿这三个级别的数据量下newSlice的内存分配情况
func BenchmarkNewSlicMillion(b *testing.B) {
	testNewSlice(SLICE_LENGTH_MILLION, b)
}

func BenchmarkNewSlicTenMillion(b *testing.B) {
	testNewSlice(SLICE_LENGTH_TEN_MILLION, b)
}

func BenchmarkNewSlicHundredMillion(b *testing.B) {
	testNewSlice(SLICE_LENGTH_HUNDRED_MILLION, b)
}
  • 执行以下命令测试,只会匹配到上面新增的三个测试方法
go test -bench='Million$' -benchmem .
  • 同一方法,处理不同数量级内容的对比测试结果如下,可见不指定容量的切片存入数据时,数据量越大,对性能的影响越严重
go test -bench='Million$' -benchmem .
goos: darwin
goarch: arm64
pkg: benchmark-demo
BenchmarkNewSlicMillion-8         67    16283754 ns/op  41678145 B/op    38 allocs/op
BenchmarkNewSlicTenMillion-8       7   159938941 ns/op  492000525 B/op   49 allocs/op
BenchmarkNewSlicHundredMillion-8   1  2242365417 ns/op  4589008224 B/op  60 allocs/op
  • 至此,基准测试的内存篇就完成了,相信大家对benchmark的基本功能已经掌握,接下来的《提高篇》会有更多进阶内容,协助咱们完成更加全面精确的基准测试,敬请期待,欣宸原创,必不让您失望

你不孤单,欣宸原创一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 数据库+中间件系列
  6. DevOps系列

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/346776.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

回溯算法章末总结

组合问题的特点 &#xff08;1&#xff09;abba 选中a之后&#xff0c;就不再选了 &#xff08;2&#xff09;找出所有的组合 &#xff08;长度可以不相等&#xff09; 组合问题模板 做回溯题步骤 &#xff08;0&#xff09;判断问题类型 &#xff08;1&#xff09;树状图 …

【百度 JavaScript API v3.0】LocalSearch 位置检索、Autocomplete 结果提示

地名检索移动到指定坐标 需求 在输入框中搜索&#xff0c;在下拉列表中浮动&#xff0c;右侧出现高亮的列表集。选中之后移动到指定坐标。 技术点 官网地址&#xff1a; JavaScript API - 快速入门 | 百度地图API SDK 开发文档&#xff1a;百度地图JSAPI 3.0类参考 实现 …

Pillow图像处理(PIL.Image类的详细使用)

文章目录Opencv、Matplotlib(plt)、Pillow(PIL)、Pytorch读取数据的通道顺序Python图像处理库&#xff08;PIL、Pillow、Scikit-image、Opencv&#xff09;Pillow 官方文档&#xff08;超详细&#xff0c;超推荐&#xff09;一、PIL库与Pillow库的区别二、Pillow库&#xff08;…

Vue3 目录结构

Vue3 目录结构 架构搭建 请确保你的电脑上成功安装 Node.js&#xff0c;本项目使用 Vite 构建工具&#xff0c;需要 Node.js 版本 > 12.0.0。 查看 Node.js 版本&#xff1a; node -v建议将 Node.js 升级到最新的稳定版本&#xff1a; 使用 nvm 安装最新稳定版 Node.js…

使用docker配置mysql主从复制

1.新建主服务器容器实例&#xff1a; docker run -p 3307:3306 --name mysql \ -v /docker/mysql/data:/var/lib/mysql \ -v /docker/mysql/conf:/etc/mysql/conf \ -v /docker/mysql/log:/var/log/mysql \ -e MYSQL_ROOT_PASSWORDroot \ -d mysql:5.7 设置容器卷之后&#xf…

Java网络编程之UDP和TCP套接字

文章目录一. 网络编程概述二. UDP网络编程1. UDP套接字2. UDP客户端回显服务器程序2.1 UDP回显服务器2.2 UDP客户端2.3 UDP实现查词典的服务器三. TCP网络编程1. TCP套接字2. TCP客户端回显服务器程序2.1 TCP回显服务器2.2 TCP客户端2.3 解决服务器无法同时出力多个客户端的问题…

牛客专访ChatGPT:2023校园招聘如何做?附校招趋势

春招在即&#xff0c;牛客作为新一代数智化校园招聘引领者&#xff0c;为大家采访了当下“顶流ChatGPT”&#xff0c;关于近几年校园招聘的变化及2023企业做校招的建议。以下&#xff0c;为“ChatGPT专访”实录。01. ChatGPT眼中近3年校园招聘的变化牛客&#xff1a;很高兴作为…

Unity Material详解

一、创建 二、属性 1.Shader:Unity内置了一些shader&#xff0c;用户自定义的shader也在这里出现. Edit: 可以编辑一些shader可编辑的内容&#xff0c;如一些属性. 2.Rendering Mode:渲染模式 Opaque-不透明-石头适用于所有的不透明的物体Cutout-镂空-破布透明度只有0%和100…

go语言环境配置 项目启动

一 安装go语言 go语言各个版本之间兼容性比较差。所以可能你需要安装固定的版本 1 安装最新版的go brew install go2 查看go可以安装的版本 brew search go3 安装指定版本的go brew install go1.134 查看安装的go语言的版本 go version5 查看go的安装路径 which go || w…

【软件测试】稳定性测试怎么做,这篇文章彻底讲透了~

稳定性对产品的重要性不言而喻。 而作为质量保障&#xff0c;在稳定性测试方面的探索也在不断演化。记得两年前我们做稳定性测试还是基于恒定的压力&#xff0c;7*24小时长时间运行&#xff0c;关注的指标无非是吞吐量TPS的抖动、响应时间的变化趋势&#xff0c;以及各种资源是…

《机器学习系统:设计和实现》读后感和一些思考

目录 计算图、编译器前端、编译器后端 计算图 计算图的作用 计算图的组成 静态计算图与动态计算图 编译器前端 IR中间表示 机器学习框架的中间表示 常见编译器前端优化方法 编译器后端 概述 通用硬件优化&#xff1a;算子拆分和算子融合 算子信息 数据精度和存储…

opencv访问图像(MAT)的属性

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人的博客_CSDN博客-微信小程序,前端,python领域博主lqj_本人擅长微信小程序,前端,python,等方面的知识https://blog.csdn.net/lbcyllqj?spm1011.2415.3001.5343哔哩哔哩欢迎关注…

设计模式:装饰模式

1、装饰模式 1&#xff09;定义 动态&#xff08;组合&#xff09;地给一个对象增加一些额外的职责。就增加功能而言&#xff0c;Decorator模式比生成子类&#xff08;继承&#xff09;更为灵活&#xff08;消除重复代码&减少子类个数&#xff09;。 2&#xff09;动机&…

Harbor安装部署实战详细手册

文章目录前言一、安装docker二、安装docker-compose1.下载2.赋权3.测试三、安装harbor1.下载2.解压3.修改配置文件4.部署5.配置开机自启动6.登录验证7.补充说明四、harbor使用问题1.docker login问题&#xff1a;Error response from daemon: Get https://: http: server gave …

Ubuntu 安装 Qt5.7.0

下载 地址&#xff1a;https://download.qt.io/https://download.qt.io/ 文件夹说明&#xff1a; snapshots&#xff1a;预览版&#xff0c;该文件夹中包含最新的测试版本。 online&#xff1a;在线安装包。 official_releases&#xff1a;最终发布版。 new_archive&#…

netcore构建webservice以及调用的完整流程

目录构建前置准备编写服务挂载服务处理SoapHeader调用添加服务调用服务补充内容构建 前置准备 框架版本要求&#xff1a;netcore3.1以上 引入nuget包 SoapCore 编写服务 1.编写服务接口 示例 using System.ServiceModel;namespace Services;[ServiceContract(Namespace &…

Elasticsearch 安装(二)

目录前言一、Linux 安装1、下载安装包⑴、选择需要的安装包⑵、下载解压到安装目录2、查看解压后目录结构3、启动 Elasticsearch⑴、正常启动流程⑵、启动过程遇到的问题①、启动报错②、创建运行 Elasticsearch 的用户&#xff0c;启动成功&#xff0c;但无法访问③、停止Elas…

【pytorch框架】对模型知识的基本了解

文章目录TensorBoard的使用1、TensorBoard启动&#xff1a;2、使用TensorBoard查看一张图片3、transforms的使用pytorch框架基础知识1 nn.module的使用2 nn.conv2d的使用3、池化(MaxPool2d)4 非线性激活5 线性层6 Sequential的使用7 损失函数与反向传播8 优化器9 对现有网络的使…

Flink X Hologres 构建企业级 Streaming Warehouse

摘要&#xff1a;本文整理自阿里云资深技术专家&#xff0c;阿里云 Hologres 负责人姜伟华&#xff08;果贝&#xff09;&#xff0c;在 FFA 实时湖仓专场的分享。本篇内容主要分为四个部分&#xff1a;实时数仓分层的技术需求阿里云一站式实时数仓 Hologres 介绍Flink x Holog…

30个题型+代码(冲刺2023蓝桥杯)

愿意的可以跟我一起刷&#xff0c;每个类型做1~5题 &#xff0c;4月前还可以回来系统复习 2月13日 ~ 3月28日&#xff0c;一共32天 一个月时间&#xff0c;0基础省三 --> 省二&#xff1b;基础好点的&#xff0c;省二 --> 省一 目录 &#x1f33c;前言 &#x1f33c…