Go语言测试第二弹——基准测试
在前一篇文章中,我们讲解了Go语言中最基础的单元测试,还没有看过的可以自行去查看,这篇文章我们详细了解Go语言里面的基准测试。
基准测试
基准测试,也就是BenchmarkTest
,基准测试是用来测试代码性能的的一种方法,使用基准测试时,测试函数必须以Benchmark
开头,后面跟具体需要测试的函数的名称,基本格式如下:
// Add函数对应的基准测试函数
func BenchmarkAdd(b *testing.B){}
基准测试函数中的参数是b *testing.B
,基准测试时函数必须要执行b.N
次,只有这样测试才能具有参考性和一定的准确性。b.N
这个值并不是固定的,而是根据情况变化,从1
开始,如果当前测试函数能够在1
秒内执行完毕,则会将b.N
的值增加到2
,如果测试函数同样在1
秒内执行完毕,则会继续增加b.N
的值,b.N
的递增序列为1,2,3,5,10,20,30,50,100
。
基本使用
现在我们先写一个计算斐波拉契数列的函数:
// Fib 递归函数计算斐波拉契数列的第 x 个数
func Fib(x int) int {if x <= 1 {return x}return Fib(x-1) + Fib(x-2)
}
然后在对应的测试文件中写上针对Fib
函数的基准测试函数:
func BenchmarkFib(b *testing.B) {for i := 0; i < b.N; i++ {Fib(10)}
}
在功能函数和基准测试函数都准备完毕之后我们可以使用go test
命令来执行对应的基准测试,使用该命令不能直接运行基准测试,需要在参数后面指定-bench
参数并指定响应的函数名称。
PS C:\Users\lee\GolandProjects\test\calc> go test -bench=Fib
goos: windows
goarch: amd64
pkg: test/calc
cpu: Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz
BenchmarkFib-8 4861580 235.1 ns/op
PASS
ok test/calc 1.567s
上面的输出中,上面都是一些系统相关信息,下面BenchmarkFib-8
后面的数字表示的是GOMAXPROCS
,默认等于CPU的核数,后面的4861580
和235.1 ns/op
表示当前测试用例执行的4861580
次,平均花费时间为235.1 ns
,总耗时为1.567s
。
在使用的时候还可以通过其他参数来获取更多的测试数据,用来提升测试的准确率和可参考性。
使用-benchmem
参数来获取内存分配的数据。
PS C:\Users\lee\GolandProjects\test\calc> go test -bench=Fib -benchmem
goos: windows
goarch: amd64
pkg: test/calc
cpu: Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz
BenchmarkFib-8 4749666 251.0 ns/op 0 B/op 0 allocs/op
PASS
ok test/calc 1.609s
在耗时的后面新增了0 B/op
和0 allocs/op
,其中0 B/op
表示每次运行测试分配了0B
的内存,0 allocs/op
表示每次运行测试进行了0
次的内存分配,因为我们的功能函数没用到额外的内存,所以这两个值都是0
,大家可以自己尝试其他方法来看看这个值的变化。
使用-benchtime
参数指定测试的基准时间或次数,在前面我们说过测试用例会执行b.N
次,这个数量是动态变化的,只要运行测试用例的时间没有超过1
秒就会递增这个值。现在可以使用-benchtime
参数指定这个基准时间,如果修改为5
,可以使用-benchtime=5s
,则表示执行时间不超过5
秒,就会递增b.N
。
PS C:\Users\lee\GolandProjects\test\calc> go test -bench=Fib -benchtime=5s
goos: windows
goarch: amd64
pkg: test/calc
cpu: Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz
BenchmarkFib-8 23184202 235.6 ns/op
PASS
ok test/calc 5.859s
通过上面的输出可以看到,一共运行了23184202
次,平均每次耗时235.6 ns
,总耗时5.859s
。因为通过-benchtime
指定了基准时间为5
秒,所以总运行次数大概是之前的5
倍。
-benchtime
除了指定时间之外,还可以用来指定具体的次数,假设指定执行100
次,可以使用-benchtime=100x
PS C:\Users\lee\GolandProjects\test\calc> go test -bench=Fib -benchtime=100x
goos: windows
goarch: amd64
pkg: test/calc
cpu: Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz
BenchmarkFib-8 100 487.0 ns/op
PASS
ok test/calc 0.167s
上面可以看到通过-benchtime
指定次数后,一共调用了Fib
函数100
次,总耗时0.167s
。
-count
参数可以用来指定测试的轮数,比如指定执行3轮。
PS C:\Users\lee\GolandProjects\test\calc> go test -bench=Fib -count=3
goos: windows
goarch: amd64
pkg: test/calc
cpu: Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz
BenchmarkFib-8 4641591 261.0 ns/op
BenchmarkFib-8 5031808 238.0 ns/op
BenchmarkFib-8 5103565 245.1 ns/op
性能比较
在基准测试中,某些功能函数在不同的输入时,相对应的性能也会有所差别,在前面的所有测试中,我们传递的参数都是10,也就是每次都计算的是斐波拉契数列的第10个,如果我们需要测试一个函数在不同的输入下的性能差异,或者是测试两个函数在相同输入下的性能差异,就会使用到性能比较的测试方法,在比较性能的时候就需要使用到一个带参数的测试函数,再使用其他的Benchmark
函数传入不同的值来调用,用以测试不同输入的性能差别。
我们将上面的测试代码修改如下:
func benchmarkFib(b *testing.B, n int) {for i := 0; i < b.N; i++ {Fib(n)}
}func BenchmarkFib2(b *testing.B) {benchmarkFib(b, 2)
}func BenchmarkFib10(b *testing.B) {benchmarkFib(b, 10)
}func BenchmarkFib20(b *testing.B) {benchmarkFib(b, 20)
}func BenchmarkFib30(b *testing.B) {benchmarkFib(b, 30)
}
在代码中写了一个带有参数的辅助函数benchmarkFib
,可以传入参数,并且构造了4个测试用例,分别传入不同的参数,执行上面的测试用例。
PS C:\Users\lee\GolandProjects\test\calc> go test -bench=Fib
goos: windows
goarch: amd64
pkg: test/calc
cpu: Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz
BenchmarkFib2-8 304879520 3.793 ns/op
BenchmarkFib10-8 5249786 232.8 ns/op
BenchmarkFib20-8 41760 28409 ns/op
BenchmarkFib30-8 345 3571588 ns/op
PASS
ok test/calc 6.245s
可以看到,在不同的输入下,函数的执行次数和平均执行时间都有不小的差距,当计算第30
个数的时候一共才执行了345
次,而每次的平均执行时间为3571588 ns
。
重置时间
在进行基准测试的时候,通常都是用来测试函数的性能,我们上面的函数都是简单的一些示例,但是在日常的工作中,我们测试之前可能需要有一些准备工作,例如测试前读取文件,这样的话在测试的时候就会将读取文件的耗时也计算到测试报告里面去,这个时候我们可以使用到ResetTimer
来重置时间,代码如下:
func BenchmarkFib(b *testing.B) {// sleep 3秒,模拟测试前的准备工作time.Sleep(time.Second * 3)// 重置定时器b.ResetTimer()for i := 0; i < b.N; i++ {Fib(10)}
}
在代码中调用了b.ResetTimer()
方法,这样就表示重置定时器,意味着这行代码之前的所有代码的耗时都不会被计算到测试中,这样能够确保代码测试的准确性。
相关文章:
Go语言测试第二弹——基准测试
在前一篇文章中,我们讲解了Go语言中最基础的单元测试,还没有看过的可以自行去查看,这篇文章我们详细了解Go语言里面的基准测试。 基准测试 基准测试,也就是BenchmarkTest,基准测试是用来测试代码性能的的一种方法&…...

关于“刘亦菲为什么无人敢娶”的问题❗❗❗
关于“刘亦菲为什么无人敢娶”的问题, 实际上涉及到多个方面的因素, 以下是对这些因素的详细分析:1.事业心重:刘亦菲作为华语影视圈的知名女星,她的演艺事业非常成功, 这也意味着她将大量的时间和精力投…...

LeetCode:经典题之141、142 题解及延伸
系列目录 88.合并两个有序数组 52.螺旋数组 567.字符串的排列 643.子数组最大平均数 150.逆波兰表达式 61.旋转链表 160.相交链表 83.删除排序链表中的重复元素 389.找不同 1491.去掉最低工资和最高工资后的工资平均值 896.单调序列 206.反转链表 92.反转链表II 141.环形链表 …...

rk3568 OpenHarmony 串口uart与电脑通讯开发案例
一、需求描述: rk3568开发板运行OpenHarmony4.0,通过开发板上的uart串口与电脑进行通讯,相互收发字符串。 二、案例展示 1、开发环境: (1)rk3568开发板 (2)系统:OpenHar…...
canvas画布旋转问题
先说一下为什么要旋转的目的:因为在画布上签名,在不同的设备上我需要不同方向的签名图片,电脑是横屏,手机就是竖屏,所以需要把手机的签名旋转270,因此写了这个方法。 关于画布旋转的重点就是获取到你的画布…...

vue3 【提效】自动导入框架方法 unplugin-auto-import 实用教程
是否还在为每次都需要导入框架方法而烦恼呢? // 每次都需手动导入框架方法 import { ref } from vuelet num ref(0)用 unplugin-auto-import 来帮你吧,以后只需这样写就行啦! let num ref(0)官方示例如下图 使用流程 1. 安装 unplugin-au…...

clip系列改进Lseg、 group ViT、ViLD、Glip
Lseg 在clip后面加一个分割head,然后用分割数据集有监督训练。textencoder使用clip,frozen住。 group ViT 与Lseg不同,借鉴了clip做了真正的无监督学习。 具体的通过group block来做的。使用学习的N个group token(可以理解为聚类…...
Ubuntu下TensorRT与trtexec工具的安装
新版(这里测试的是10.1版)的onnx转tensorrt engine工具trtexec已经集成在TensorRT中,不需要额外单独安装。 教程来源于此网页:https://medium.com/moshiur.faisal01/install-tensorrt-with-command-line-wrapper-trtexec-on-unun…...
MySQL定时任务
事件调度器操作 查看事件调度器是否开启:ON 表示已开启。 show variables like %event_scheduler%; ------------------------ | Variable_name | Value | ------------------------ | event_scheduler | ON | ------------------------ 开启和关闭事件调度器…...
Pandas实用Excel数据汇总
Pandas 是一个开源的 Python 库,由 Wes McKinney 开发,专门用于高效地处理和分析数据,无论是小规模的数据实验还是大规模的数据处理任务。它构建在 NumPy 之上,这意味着它利用了 NumPy 的高性能数组计算能力。Pandas 的核心数据结…...

【计算机网络】[第4章 网络层][自用]
1 概述 (1)因特网使用的TCP/IP协议体系(四层)的网际层,提供的是无连接、不可靠的数据报服务; (2)ATM、帧中继、X.25的OSI体系(七层)中的网络层,提供的是面向连接的、可靠的虚电路服务。 (3)路由选择分两种: 一种是由用户or管理员人工进行配置(只适用于规…...
Unity3D Entity_CacheService实现详解
Unity3D是一款广泛使用的游戏开发引擎,它提供了丰富的功能和工具来帮助开发者创建高质量的游戏和互动体验。在Unity开发过程中,资源管理是一个重要的环节,特别是当项目规模逐渐增大,资源数量变多时。为了优化资源的加载和管理&…...

DLMS/COSEM协议—(Green-Book)Gateway protocol
DLMS/COSEM协议 — Gateway protocol 10.10 Gateway protocol (网关协议)10.10.1 概述10.10.2 网关协议 (The gateway protocol)10.10.3 HES在WAN/NN中作为发起者(拉取操作)10.10.4 LAN中的终端设备作为发起…...
Android高级面试_12_项目经验梳理
Android 高级面试-1:Handler 相关 问题:Handler 实现机制(很多细节需要关注:如线程如何建立和退出消息循环等等) 问题:关于 Handler,在任何地方 new Handler 都是什么线程下? 问题:…...

【项目实训】解决前后端跨域问题
由于前端框架使用vue,后端使用flask,因此需要解决前后端通信问题 在vue.config.js中修改 module.exports defineConfig({transpileDependencies: true,lintOnSave:false, }) // 跨域配置 module.exports {devServer: { //记住&#x…...
Java反射API详解与应用场景
一、Java反射API简介: 一、什么是反射: 反射是一种强大的工具,它允许我们在运行时检查类、方法和字段的信息,甚至允许我们动态的调用特定类的方法或改变字段的值。编程语言中的反射机制通常用于从类、对象或方法中检索元数据,或者更特别的说,从代码本身中获取信息。这就…...

【例子】webpack 开发一个可以加载 markdown 文件的加载器 loader 案例
Loader 作为 Webpack 的核心机制,内部的工作原理却非常简单。接下来我们一起来开发一个自己的 Loader,通过这个开发过程再来深入了解 Loader 的工作原理。 这里我的需求是开发一个可以加载 markdown 文件的加载器,以便可以在代码中直接导入 m…...

揭秘!这款电路设计工具让学校师生都爱不释手——SmartEDA的魔力何在?
随着科技的飞速发展,电子设计已成为学校师生们不可或缺的技能之一。而在众多的电路设计工具中,有一款名为SmartEDA的工具,凭借其强大的功能和友好的用户体验,迅速赢得了广大师生的青睐。今天,就让我们一起探索SmartEDA…...
onlyoffice实现打开文档的功能
后端代码 import api from api import middlewareasync def doc_callback(request):data await api.req.get_json(request)print("callback ", data)# status 2 文档准备好被保存# status 6 文档编辑会话关闭return api.resp.success()app api.Api(routes[api.…...

基于 SpringBoot + Vue 的图书购物商城项目
本项目是一个基于 SpringBoot 和 Vue 的图书购物商城系统。系统主要实现了用户注册、登录,图书浏览、查询、加购,购物车管理,订单结算,会员折扣,下单,个人订单管理,书籍及分类管理,用…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...

HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...

微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...