欢迎访问我的GitHub

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

本篇概览

-《Go语言基准测试(benchmark)三部曲》已近尾声,经历了《基础篇》和《内存篇》的实战演练,相信您已熟练掌握了基准测试的常规操作以及各种参数的用法,现在可以学习一些进阶版的技能了,在面对复杂一些的场景也能高效完成基准测试,另外还有几个坑也要提前了解,避免以后掉进去

ResetTimer

  • 有时候,在基准测试前会有些准备工作,这些准备工作的耗时会影响基准测试的结果,举例如下,BenchmarkFib是常规的基准测试,而BenchmarkFibWithPrepare多了八百毫秒的准备时间
func BenchmarkFib(b *testing.B) {
for n := 0; n < b.N; n++ {
fib(30)
}
} // BenchmarkFibWithPrepare 进入正式测试前需要耗时做准备工作的case
func BenchmarkFibWithPrepare(b *testing.B) {
// 假设这里有个耗时800毫秒的初始化操作
<-time.After(800 * time.Millisecond) // 这下面才是咱们真正想做基准测试的代码
for n := 0; n < b.N; n++ {
fib(30)
}
}
  • 同时执行上述两个基准测试,命令和结果如下,可见因为准备工作的耗时,BenchmarkFibWithPrepare方法的测试结果远不及BenchmarkFib,这与事实是不符合的,因为BenchmarkFibWithPrepare方法的测试目标没有变化,但是因为自身的准备工作导致测试结果出现较大偏差
go test -bench='BenchmarkFib|BenchmarkFibWithPrepare' benchmark-demo
goos: darwin
goarch: arm64
pkg: benchmark-demo
BenchmarkFib-8 325 3637442 ns/op
BenchmarkFibWithPrepare-8 50 20173566 ns/op
PASS
ok benchmark-demo 14.871s
  • 解决上述问题的思路是不要将准备工作的耗时算入基准测试,实现起来很简简,如下图黄色箭头所示,b.ResetTimer()重置了计时器,前面的耗时都与基准测试无关

  • 再做一次基准测试,结果如下,可见800毫秒带来的偏差已被去除
go test -bench='BenchmarkFib|BenchmarkFibWithPrepare' benchmark-demo
goos: darwin
goarch: arm64
pkg: benchmark-demo
BenchmarkFib-8 325 3616239 ns/op
BenchmarkFibWithPrepare-8 316 3729323 ns/op
PASS
ok benchmark-demo 5.628s

StopTimer & StartTimer

  • 前面通过ResetTimer消除了基准测试前的多余耗时,但是如果多余的耗时出现在基准测试过程中呢?代码如下所示,fib是本次测试的目标,如果每次fib结束后都要做一些耗时的清理工作(这里用10毫秒延时来模仿),才能再次fib,那又该如何消除这10毫秒对基准测试的影响呢?
func BenchmarkFibWithClean(b *testing.B) {
// 这下面才是咱们真正想做基准测试的代码
for n := 0; n < b.N; n++ {
fib(30) // 假设这里有个耗时100毫秒的清理操作
<-time.After(10 * time.Millisecond)
}
}
  • 先来看看每次fib之后的10毫秒是否会影响基准测试,执行测试的命令和测试结果如下,可见,和没有任何耗时的BenchmarkFib方法相比,BenchmarkFibWithClean的测试结果与fib的真实性能相去甚远
go test -bench='BenchmarkFib$|BenchmarkFibWithClean' benchmark-demo
goos: darwin
goarch: arm64
pkg: benchmark-demo
BenchmarkFib-8 322 3610100 ns/op
BenchmarkFibWithClean-8 81 16139196 ns/op
PASS
ok benchmark-demo 3.002s
  • 对于这种每次调用fib之前或者之后都会出现的额外耗时操作,可以用b.StartTimer()和b.StopTimer()的组合来消除掉,简单的说就是StartTimer会开启基准测试的计时,StopTimer会暂停计时,具体的使用方法如下
// BenchmarkFibWithClean 假设每次执行完fib方法后,都要做一次清理操作
func BenchmarkFibWithClean(b *testing.B) {
// 这下面才是咱们真正想做基准测试的代码
for n := 0; n < b.N; n++ {
// 继续记录耗时
b.StartTimer() fib(30) // 停止记录耗时
b.StopTimer() // 假设这里有个耗时100毫秒的清理操作
<-time.After(10 * time.Millisecond)
}
}
  • 再次测试,结果如下,去除了多余耗时的基准测试结果,从之前16139196ns恢复到7448678ns,然而,和原始的没有任何处理的BenchmarkFib结果相比依然有一倍左右的差距,看来StartTimer和StopTimer本身也会带来耗时,而且在纳秒级别的测试中会显得非常明显
go test -bench='BenchmarkFib$|BenchmarkFibWithClean' benchmark-demo
goos: darwin
goarch: arm64
pkg: benchmark-demo
BenchmarkFib-8 325 3631020 ns/op
BenchmarkFibWithClean-8 241 7448678 ns/op
PASS
ok benchmark-demo 7.751s

危险用法,提前避开

  • 现在咱们对benchmark的了解已经比较全面了,可以覆盖大多数单元测试场景,下面有两个反面教材,希望咱们将来都能提前避免类似错误
  • 这两个反面教材比较类似:对b.N的错误使用
  • 第一个错误用法如下所示,在执行b.N次循环的时候,将当前是第几次作为入参传入了被测试的方法fib
// BenchmarkFibWrongA 演示了错误的基准测试代码,这样的测试可能无法结束
func BenchmarkFibWrongA(b *testing.B) {
for n := 0; n < b.N; n++ {
fib(n)
}
}
  • 上述代码在基准测试的时候可能永远不会结束,这是因为b.N的值并不固定,可能超出了fib方法的设计范围,这样就导致出现意料之外的结果(本意是性能测试,fib的入参应该是设计范围内的),实际运行效果如下,红色箭头指向的状态一直在等待中,只能强行关闭了

  • 第二种反面教材也类似,不过更简单,直接拿b.N作为入参,只调用一次fib方法,代码如下所示
func BenchmarkFibWrongB(b *testing.B) {
fib(b.N)
}
  • 和前面的BenchmarkFibWrongA比,fib的执行次数似乎少了,但是请注意:b.N到底是多少呢?是否在fib方法的设计范围内?依旧没有明确答案,因此,代码也有可能永远不会结束
  • 以本例中的fib为例,实际功能是斐波那契数列,我这边入参等于50的时候,fib方法的耗时是54秒,所以,如果b.N的值再大一些,例如等于100的时候,fib方法就要计算很久了,而计算较大值并不是我们做基准测试的意图
  • 至此,Go语言基准测试(benchmark)三部曲就全部完成了,相信此刻的您对除了信心满满,还有就是迫不及待的想去写上一段benchmark代码,看看自己的方法函数究竟性能如何吧
  • 希望这三篇文章能给您带来一些参考,golang学习路上,欣宸一路相伴

欢迎关注博客园:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...

Go语言基准测试(benchmark)三部曲之三:提高篇的更多相关文章

  1. SQL注入攻击三部曲之进阶篇

    SQL注入攻击三部曲之进阶篇 通过入门篇的学习,我们知道了SQL注入攻击的判断方法,但是如果想侵入网站,获取网站的机密内容,那么仅靠入门篇的知识是无法达到的.本篇文章我们将进一步的分析SQL注入攻击. ...

  2. Java提高篇——对象克隆(复制)

    假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short, ...

  3. java提高篇(二)-----理解java的三大特性之继承

    在<Think in java>中有这样一句话:复用代码是Java众多引人注目的功能之一.但要想成为极具革命性的语言,仅仅能够复制代码并对加以改变是不够的,它还必须能够做更多的事情.在这句 ...

  4. java提高篇(二)-----理解java的三大特性之继承

    在<Think in java>中有这样一句话:复用代码是Java众多引人注目的功能之一.但要想成为极具革命性的语言,仅仅能够复制代码并对加以改变是不够的,它还必须能够做更多的事情.在这句 ...

  5. (转)java提高篇(二)-----理解java的三大特性之继承

    在<Think in java>中有这样一句话:复用代码是Java众多引人注目的功能之一.但要想成为极具革命性的语言,仅仅能够复制代码并对加以改变是不够的,它还必须能够做更多的事情.在这句 ...

  6. SQL注入攻击三部曲之高级篇

    SQL注入攻击三部曲之高级篇 经过了入门篇和进阶篇的学习,相信诸位想要破解一般的网站是没有什么问题了,但是先别得意.正所谓学海无涯,技术的进步也是没有止境的.SQL注入是一个看起来简单,但是变数很多的 ...

  7. Java 学习笔记提高篇

    Java笔记(提高篇)整理   主要内容: 面向对象 异常 数组 常用类 集合 IO流 线程 反射 Socket编程 1.  面向对象 1.1包 用来管理Java中的类, 类似文件夹管理文件一样. 因 ...

  8. Java提高篇之理解java的三大特性——继承

    在<Think in java>中有这样一句话:复用代码是Java众多引人注目的功能之一.但要想成为极具革命性的语言,仅仅能够复制代码并对加以改变是不够的,它还必须能够做更多的事情.在这句 ...

  9. 【转】java提高篇(二)-----理解java的三大特性之继承

    [转]java提高篇(二)-----理解java的三大特性之继承 原文地址:http://www.cnblogs.com/chenssy/p/3354884.html 在<Think in ja ...

  10. kubernetes下的Nginx加Tomcat三部曲之三:实战扩容和升级

    本章是<kubernetes下的Nginx加Tomcat三部曲系列>的终篇,今天咱们一起在kubernetes环境对下图中tomcat的数量进行调整,再修改tomcat中web工程的源码, ...

随机推荐

  1. 我是如何组织 Go 代码的(目录结构 依赖注入 wire)

    背景 对于大多数 Gopher 来说,编写 Go 程序会直接在目录建立 main.go,xxx.go,yyy.go-- 不是说不好,对于小型工程来说,简单反而简洁明了,我也提倡小工程没必要整一些花里胡 ...

  2. 2023-07-18:给你一个正整数数组 nums,请你移除 最短 子数组(可以为 空), 使得剩余元素的 和 能被 p 整除。 不允许 将整个数组都移除。 请你返回你需要移除的最短子数组的长度,如果

    2023-07-18:给你一个正整数数组 nums,请你移除 最短 子数组(可以为 空), 使得剩余元素的 和 能被 p 整除. 不允许 将整个数组都移除. 请你返回你需要移除的最短子数组的长度,如果 ...

  3. nginx配置文件内容(1)

    nginx.conf内容 在Nginx服务器的主配置文件nginx.conf中,包括全局配置.I/O事件配置.HTTP配置这三大块内容,配置语句的格式为"关键字  值:"(末尾以分 ...

  4. 介绍Centos7启用过程中用到的rpm软件包、及其作用

    序号 包名 作用 1 udev 系统设备管理器,用于管理设备驱动程序和设备的元数据. 2 lvm2 Logical Volume Manager 2(LVM2)是一个用于管理和分配存储设备的工具,允许 ...

  5. mysql-workbench-community报错解决办法

    输入以下命令: sudo apt-get -f install 参考链接:https://www.jianshu.com/p/767c9a29b403

  6. 快速掌握Vue3:速成Vue3前端开发看这篇就够啦

    一.Vue基本概念 1.1-Vue3的优点 Vue3支持Vue2额大多数特性. 更好的支持TypeScript. 打包大小减少41%. 初次渲染快55%,更新渲染快133%. 内存减少54%. 使用p ...

  7. 犯得一些zz错误

    本文用于警戒自己,不要再犯以前的傻逼错误 noip没建子文件夹导致爆零 知道关同步流之后还用endl,导致超时 使用'\n'代替endl 3.多组测试数据使用for循环占用了 i 变量名,后面在for ...

  8. RocketMQ Linux单机测试:简易快速部署指南及Dashboard控制台部署

    目录 简介 开始 下载 增加环境变量 修改启动文件jvm大小 修改rocketmq配置文件 启动 快速测试 关闭 Dashboard 下载Dashboard 已编译jar包网盘下载 启动命令 可能遇到 ...

  9. Dirty-Pipe Linux内核提权漏洞(CVE-2022-0847)

    前言: 划水一波,哈哈,以后复现漏洞不再直接傻瓜无脑的走流程了,首先码字写加构思比较麻烦且写的不多还效率不高,现在就是当做见到了一个漏洞,在此记录一下这个漏洞,包括其来源,简单的描述,适用范围,以及其 ...

  10. K210 调节颜色阈值识别红绿黄三色

    官方在机器视觉的API中提供了寻找绿色色块的例程 https://wiki.sipeed.com/soft/maixpy/zh/api_reference/machine_vision/image/i ...