当前位置: 首页 > news >正文

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的核数,后面的4861580235.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/op0 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语言测试第二弹——基准测试

在前一篇文章中&#xff0c;我们讲解了Go语言中最基础的单元测试&#xff0c;还没有看过的可以自行去查看&#xff0c;这篇文章我们详细了解Go语言里面的基准测试。 基准测试 基准测试&#xff0c;也就是BenchmarkTest&#xff0c;基准测试是用来测试代码性能的的一种方法&…...

关于“刘亦菲为什么无人敢娶”的问题❗❗❗

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

LeetCode:经典题之141、142 题解及延伸

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

rk3568 OpenHarmony 串口uart与电脑通讯开发案例

一、需求描述&#xff1a; rk3568开发板运行OpenHarmony4.0&#xff0c;通过开发板上的uart串口与电脑进行通讯&#xff0c;相互收发字符串。 二、案例展示 1、开发环境&#xff1a; &#xff08;1&#xff09;rk3568开发板 &#xff08;2&#xff09;系统&#xff1a;OpenHar…...

canvas画布旋转问题

先说一下为什么要旋转的目的&#xff1a;因为在画布上签名&#xff0c;在不同的设备上我需要不同方向的签名图片&#xff0c;电脑是横屏&#xff0c;手机就是竖屏&#xff0c;所以需要把手机的签名旋转270&#xff0c;因此写了这个方法。 关于画布旋转的重点就是获取到你的画布…...

vue3 【提效】自动导入框架方法 unplugin-auto-import 实用教程

是否还在为每次都需要导入框架方法而烦恼呢&#xff1f; // 每次都需手动导入框架方法 import { ref } from vuelet num ref(0)用 unplugin-auto-import 来帮你吧&#xff0c;以后只需这样写就行啦&#xff01; let num ref(0)官方示例如下图 使用流程 1. 安装 unplugin-au…...

clip系列改进Lseg、 group ViT、ViLD、Glip

Lseg 在clip后面加一个分割head&#xff0c;然后用分割数据集有监督训练。textencoder使用clip&#xff0c;frozen住。 group ViT 与Lseg不同&#xff0c;借鉴了clip做了真正的无监督学习。 具体的通过group block来做的。使用学习的N个group token&#xff08;可以理解为聚类…...

Ubuntu下TensorRT与trtexec工具的安装

新版&#xff08;这里测试的是10.1版&#xff09;的onnx转tensorrt engine工具trtexec已经集成在TensorRT中&#xff0c;不需要额外单独安装。 教程来源于此网页&#xff1a;https://medium.com/moshiur.faisal01/install-tensorrt-with-command-line-wrapper-trtexec-on-unun…...

MySQL定时任务

事件调度器操作 查看事件调度器是否开启&#xff1a;ON 表示已开启。 show variables like %event_scheduler%; ------------------------ | Variable_name | Value | ------------------------ | event_scheduler | ON | ------------------------ 开启和关闭事件调度器…...

Pandas实用Excel数据汇总

Pandas 是一个开源的 Python 库&#xff0c;由 Wes McKinney 开发&#xff0c;专门用于高效地处理和分析数据&#xff0c;无论是小规模的数据实验还是大规模的数据处理任务。它构建在 NumPy 之上&#xff0c;这意味着它利用了 NumPy 的高性能数组计算能力。Pandas 的核心数据结…...

【计算机网络】[第4章 网络层][自用]

1 概述 (1)因特网使用的TCP/IP协议体系(四层)的网际层,提供的是无连接、不可靠的数据报服务; (2)ATM、帧中继、X.25的OSI体系(七层)中的网络层,提供的是面向连接的、可靠的虚电路服务。 (3)路由选择分两种: 一种是由用户or管理员人工进行配置(只适用于规…...

Unity3D Entity_CacheService实现详解

Unity3D是一款广泛使用的游戏开发引擎&#xff0c;它提供了丰富的功能和工具来帮助开发者创建高质量的游戏和互动体验。在Unity开发过程中&#xff0c;资源管理是一个重要的环节&#xff0c;特别是当项目规模逐渐增大&#xff0c;资源数量变多时。为了优化资源的加载和管理&…...

DLMS/COSEM协议—(Green-Book)Gateway protocol

DLMS/COSEM协议 — Gateway protocol 10.10 Gateway protocol &#xff08;网关协议&#xff09;10.10.1 概述10.10.2 网关协议 &#xff08;The gateway protocol&#xff09;10.10.3 HES在WAN/NN中作为发起者&#xff08;拉取操作&#xff09;10.10.4 LAN中的终端设备作为发起…...

Android高级面试_12_项目经验梳理

Android 高级面试-1&#xff1a;Handler 相关 问题&#xff1a;Handler 实现机制&#xff08;很多细节需要关注&#xff1a;如线程如何建立和退出消息循环等等&#xff09; 问题&#xff1a;关于 Handler&#xff0c;在任何地方 new Handler 都是什么线程下? 问题&#xff1a…...

【项目实训】解决前后端跨域问题

由于前端框架使用vue&#xff0c;后端使用flask&#xff0c;因此需要解决前后端通信问题 在vue.config.js中修改 module.exports defineConfig({transpileDependencies: true,lintOnSave:false, }) // 跨域配置 module.exports {devServer: { //记住&#x…...

Java反射API详解与应用场景

一、Java反射API简介: 一、什么是反射: 反射是一种强大的工具,它允许我们在运行时检查类、方法和字段的信息,甚至允许我们动态的调用特定类的方法或改变字段的值。编程语言中的反射机制通常用于从类、对象或方法中检索元数据,或者更特别的说,从代码本身中获取信息。这就…...

【例子】webpack 开发一个可以加载 markdown 文件的加载器 loader 案例

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

揭秘!这款电路设计工具让学校师生都爱不释手——SmartEDA的魔力何在?

随着科技的飞速发展&#xff0c;电子设计已成为学校师生们不可或缺的技能之一。而在众多的电路设计工具中&#xff0c;有一款名为SmartEDA的工具&#xff0c;凭借其强大的功能和友好的用户体验&#xff0c;迅速赢得了广大师生的青睐。今天&#xff0c;就让我们一起探索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 的图书购物商城系统。系统主要实现了用户注册、登录&#xff0c;图书浏览、查询、加购&#xff0c;购物车管理&#xff0c;订单结算&#xff0c;会员折扣&#xff0c;下单&#xff0c;个人订单管理&#xff0c;书籍及分类管理&#xff0c;用…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

使用LangGraph和LangSmith构建多智能体人工智能系统

现在&#xff0c;通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战&#xff0c;比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

作为测试我们应该关注redis哪些方面

1、功能测试 数据结构操作&#xff1a;验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化&#xff1a;测试aof和aof持久化机制&#xff0c;确保数据在开启后正确恢复。 事务&#xff1a;检查事务的原子性和回滚机制。 发布订阅&#xff1a;确保消息正确传递。 2、性…...

在 Spring Boot 中使用 JSP

jsp&#xff1f; 好多年没用了。重新整一下 还费了点时间&#xff0c;记录一下。 项目结构&#xff1a; pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...

实战三:开发网页端界面完成黑白视频转为彩色视频

​一、需求描述 设计一个简单的视频上色应用&#xff0c;用户可以通过网页界面上传黑白视频&#xff0c;系统会自动将其转换为彩色视频。整个过程对用户来说非常简单直观&#xff0c;不需要了解技术细节。 效果图 ​二、实现思路 总体思路&#xff1a; 用户通过Gradio界面上…...