Go语言学习18-基准测试

2023-11-18

引言

所谓基准测试(Benchmark Test,简称BMT)是指,通过一些科学的手段实现对一类测试对象的某项性能指标进行可测量、可重复和可比对的测试。很多时候,基准测试已被狭义地称为性能测试。

基准测试

1. 编写基准测试函数

与功能测试相同,针对其他源码文件中的程序实体的基准测试程序也是以测试函数为单位的。一个基准测试函数的名称和签名如下:

func BenchmarkXxx(b *testing.B)

2. 计时器

在 *testing.B 类型中,与计时器相关的方法有3个它们是 StartTimerStopTimerResetTimer 。这3个方法被用于操纵基准测试函数的计时器。该计时器的作用是计算当前基准测试函数的执行时间。

调用 b.StartTimer 方法意味着开始对当前的测试函数的执行进行计时。它总会在开始执行基准测试函数的时候被自动地调用。这个方法被暴露出来的意义在于:计时器在被停止之后重新启动。调用 b.StopTimer 方法可以使当前测试函数的计时器停止。例如:

package bmt

import (
	"testing"
	"time"
)

func Benchmark(b *testing.B) {
	customTimerTag := false
	if customTimerTag {
		b.StopTimer()
	}
	b.SetBytes(12345678)
	time.Sleep(time.Second)
	if customTimerTag {
		b.StartTimer()
	}
}

如上文件命名为 bmt_test.go 存放到工作区的 testing/bmt 代码包中,运行基准测试截图如下:

这里写图片描述

现在将其中的 customTimerTag 变量的值改为 true ,再来运行测试,截图如下:

这里写图片描述

从上面两个运行截图可以看见最后两行的输出内容不同。在第二个截图中,倒数第二行的3个部分分别代表了当前测试函数的名称,操作次数以及操作平均耗时。其中,操作次数 是当前的基准测试函数被执行的次数,而 操作平均耗时 是当前基准测试函数的平均执行时间。

同样观察两个运行截图的倒数第二行可知,当 customTimerTagtrue 时,基准测试函数 Benchmark 可以被执行多次,而当 customTimerTagfalse 时,它往往只能获得一次执行机会。这些都是由于 testing 包中有这样的一个限制:在基准测试函数单次执行时间超过指定值(默认为1秒,也可以由标记 -benchtime 自定义)的情况下,只执行该基准测试函数一次。也就是测试运行程序会在不超过这个执行时间上限的情况下尽可能多次地执行一个基准测试函数。

customTimerTagtrue 时,在调用语句 time.Sleep(time.Second) 的之前和之后,分别停止和重启了 Benchmark 函数的计时器,这就相当于不把 time.Sleep(time.Second) 语句的执行时间算在 Benchmark 函数的执行时间之内,执行 Benchmark 函数的时间已经基本可以忽略不计了(可以从 0.00 ns/op 可知),这样测试运行程序在 Benchmark 函数的累积执行时间为到达时间上限之前就会连续不断地重复执行它。

customTimerTagfalse 时,调用语句 time.Sleep(time.Second) 让当前的测试程序“休息”1 秒,Benchmark 函数的单次执行时间就肯定会大于 1 秒。因此测试运行程序就不会对 Benchmark 函数执行第二次。

对于方法 b.ResetTimer 在被调用时,会重置当前基准测试函数的计时器,就是把该函数的执行时间重置为 0,这相当于把当前函数中在 b.ResetTimer 语句之前的所有语句的执行时间都从该函数的执行时间中减去。

3. 内存分配统计

方法 b.ReportAllocs 的含义是判断在启动当前测试的 go test 命令的后面是否有 -benchmem 标记。它会返回一个 bool 类型的结果值。

方法 b.SetBytes 接受一个 int64 类型的值,它被用于记录在单次操作中被处理的字节的数量。

customTimerTagfalse,运行截图中,针对 Benchmark 函数的操作信息的那一行信息中多处了一个部分------ 12.34MB/s 。它的含义是每秒被处理的字节的数量(以 MB 为单位)。这个数量其实等于测试运行程序在执行(可能是多次) Benchmark 函数的过程中每秒调用 b.SetBytes 方法的次数乘以传入的那个整数。

首先试想一个场景:在基准测试函数 Benchmark 中测试的是一个向文件系统中写入数据的函数。在写入成功后,会调用 b.SetBytes 方法并把真正写入的字节数作为参数传入。通过测试结果信息中的 xxx MB/s ,可以获知该函数每秒能向文件系统写入多少兆字节( MB )的数据了。

从上面总结,b.SetBytes 方法能够从输入输出(IO)的角度统计出被测试的程序实体的实际性能。

4. 基准测试的运行

在上面的测试中,go test 命令只运行了 cnet/ctcp 包中的功能测试。下面说说 go test 命令的基准测试标记说明。

标记名称 标记描述
-bench regexp 在默认情况下,go test命令不会运行任何基准测试,但可以使用该标记以执行匹配“regexp”处的
正则表达式的基准测试函数,“regexp”可以被替换成任何正则表达式。如果需要运行所有的基准测试函数,
添加 –bench . 或 –bench=. 或 –bench=“.”
-benchmem 在输出内容中包含基准测试的内存分配统计信息
-benchtime t 用来间接地控制单个基准测试函数的操作次数。这里的“t”指的是执行单个测试函数的累积耗时上限。
“t”处的内容使用的是类型time.Duration可接受的时间表示法。“t”的默认值是1s

运行针对代码包 cnet/ctcp 运行基准测试的截图如下:

这里写图片描述

结构体类型 testing.B 的字段 N 可以被用来设置对基准测试函数中的某一个代码块的重复执行次数。例如:

for i := 0; I < b.N; i++ {
	//测试代码
}

运行截图如下:

这里写图片描述

对于计算 N 的值的具体算法,可以查看标准库的 testing 包的源码文件 benchmark.go 中的相关代码。

如果要看到基准测试函数的操作次数和操作平均耗时的同时获得这个过程中的内存分配情况,就需要用到 -benchmem 标记。例如下面截图:

这里写图片描述

23416 B/op”是每次操作分配的字节的平均数为23416个。“109 allocs/op”是每次操作分配内存的次数平均为109次。

go test命令还可以接受一个可自定义测试运行次数并在测试运行期间改变Go语言最大并发处理数的标记 -cpu , -cpu 标记可以是一个整数列表,多个整数之间用逗号分隔。-cpu 标记的处理方式和 -parallel 标记相反,-parallel 标记默认使用Go语言最大并发处理数,而 -cpu 标记却会直接设置它。但是,由 -cpu 标记引发的Go语言最大并发处理数的设置操作并不会影响 -parallel 标记的默认值。因为 -parallel 标记的值是在测试运行程序初始化的时候设置的。如果在 go test 命令中没有显式地加入 -parallel 标记,则它的值会被设置为测试运行程序初始化时刻的Go语言最大并发处理数。在这个时刻,测试程序运行还没有把 -cpu 标记的值(如果有的话)解析成整数数组,也就无法使用这个数组中的整数设置Go语言最大并发处理数了。

使用 -cpu 标记运行截图如下:

这里写图片描述

测试运行程序执行基准测试函数 BenchmarkPrimeFuncs 的次数是 7,这与 -cpu 标记的值 1,2,4,8,12,16,20 中的 7 个数字相对应。上面只是展示了基准测试的运行记录,同样这边也调用了 7 次功能测试函数 TestPrimeFuncs

如上运行截图中,倒数 行的末尾包含了一行运行时环境信息:[GOMAXPROCS=20, NUM_CPU=4, NUM_GOROUTINE=2],对于第一个 GOMAXPROCS 代表Go语言最大并发处理数,此处为 20 , NUM_CPU 代表当前计算机的CPU总内核数,此处为 4NUM_GOROUTINE 代表当前时刻的并发程序的数量,此处为 2

与并发处理有关的标记

标记名称 使用示例 说明
-parallel -parallel 4 功能:设置可并发执行的功能测试函数的最大数量
默认值:调用runtime.GOMAXPROCS(0)后的结果,即Go语言最大并发处理数量
先决条件:功能测试函数需要在开始处调用结构体testing.T类型的参数值的Parallel方法
生效的测试:功能测试
-cpu -cpu 1,2,4 功能:根据标记的值,迭代的设置Go语言并发处理最大数并执行全部功能测试或全部基准测试。
迭代的次数与标记值中的整数个数一致
默认值:“”,即空字符串
先决条件:无
生效的测试:功能测试和基准测试

注意: -cpu-parallel 标记的作用域都是代码包,它们只能用于控制某一个代码包内的测试的流程。如果使用 go test 命令启动了多个代码包的测试,那么每个代码包中的功能测试永远是可并发执行的,而基准测试永远是串行执行的。如果把针对某一个代码包的所有测试的运行过程看成一个整体的话,若在执行 go test 命令时加入了 -bench 标记,则针对各个代码包的测试运行过程会被串行地执行,否则它们将被并发地执行。但无论如何,打印测试记录和结果信息的动作是严格按照 go test 命令后面的代码包从左往右的顺序执行。

结语

本篇介绍了Go语言的基准测试的相关内容,下一篇讲解Go语言的样本测试,敬请期待!!!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Go语言学习18-基准测试 的相关文章

  • Windows 上Go env 命令设置Go环境变量

    在旧版本中使用下面的命令设置 Enable the go modules feature env GO111MODULE on Set the GOPROXY environment variable env GOPROXY https g
  • Go编程技巧--io.Reader/Writer

    Go原生的pkg中有一些核心的interface 其中io Reader Writer是比较常用的接口 很多原生的结构都围绕这个系列的接口展开 在实际的开发过程中 你会发现通过这个接口可以在多种不同的io类型之间进行过渡和转化 本文结合实际
  • 开源Go语言数值算法库 An open numerical library purely based on Go programming language

    目录 关于 goNum https github com chfenger goNum 安装环境 安装方法 算法 许可证书 致谢 关于goNum goNum是一款完全以Go语言为基础的开源数值算法库 它可以使你像调用其它go函数一样使用其进
  • Go+Together——Go+1.0发布会暨Go+开发者基金会启动仪式重磅来袭!

    你想参与iPhone13抽奖吗 你想和大咖面对面交流吗 你想收获最前沿的行业动态吗 10 月15 日 Go Together Go 1 0发布会暨Go 开发者基金会启动仪式重磅来袭 活动中除七牛云 CEO Go 语言发明人许式伟以及Go 开
  • Go语言中的rune数据类型

    写在前面 最近开始学习Go语言 因为自己是从Java逐步转Go原因 在感慨Go语言简便的同时 也因为其封装的数据类型和包较多 所以还得慢慢学习 今天来谈谈Go语言中的rune数据类型 名词解释 Go语言中的整数类型也有有符号数和无符号数之别
  • go语言学习笔记1--flag代码包

    flag代码包用于接收和解析命令参数 我们以hello world代码作为示例 package main import fmt func main fmt Println hello world 现在 我们想要根据输入定制hello的对象
  • go语言标准库

    在Go语言的安装文件里包含了一些可以直接使用的包 即标准库 Go语言的标准库 通常被称为语言自带的电池 提供了清晰的构建模块和公共接口 包含 I O 操作 文本处理 图像 密码学 网络和分布式应用程序等 并支持许多标准化的文件格式和编解码协
  • golang的hijack篡取劫持

    一直不太明白golang的hijack是干什么的 只知道hijack这个词是篡取的意思 难道跟网关的作用一样 把client的请求发到这个服务上 然后这个服务帮忙转发到远端server 但是看了源码后就明白这个golang hijack是干
  • Go语言学习13-类型转换

    类型转换 引言 类型转换 1 概念 2 数值类型之间的转换 3 与string类型相关的转换 4 别名类型值之间的转换 结语 引言 在上一篇博文中 我们介绍了 Go 语言的 数据的使用 本篇博文 我们将介绍 Go 语言的类型转换 类型转换
  • Go项目配置管理工具---Viper

    目录 Viper概述 前言 功能 viper配置优先级 从Viper中获取值 读取配置文件 注册和使用别名 把值写入Viper 设置默认值 使用Set方法设置值 把配置信息写入配置文件 从io Reader中读取配置信息到viper 监控V
  • Go解析yaml和yml文件

    Go解析yaml和yml文件 文章目录 Go解析yaml和yml文件 1 yaml概述 2 功能 3 示例 4 语言的构成元素 1 清单 数组 2 关系数组 3 区块的字符 4 保留换行 Newlines preserved 5 折叠换行
  • 学习笔记(02):go快速入门-iota用法

    立即学习 https edu csdn net course play 26897 344142 utm source blogtoedu
  • GoLang学习资源清单

    地鼠文档go语言文档网站通过收集整理go语言相关的学习文档 为大家提供一个学习平台https www topgoer cn 前景 Go语言中文文档https www topgoer com 文档 Gin Web FrameworkGin W
  • Go timer 是如何被调度的?

    hi 大家好 我是 haohongfan 本篇文章剖析下 Go 定时器的相关内容 定时器不管是业务开发 还是基础架构开发 都是绕不过去的存在 由此可见定时器的重要程度 我们不管用 NewTimer timer After 还是 timer
  • go语言连接mysql数据库,并验证连通性

    go语言连接mysql数据库 并验证连通性 package main import database sql sql Open加载包 github com go sql driver mysql 没用到包里的内容但是需要加载一下这个包 lo
  • Go语言简介

    一 Go编程语言概述 Go语言也叫Golang 是由谷歌 Google 公司在2007年推出的一款静态编译型语言 主要将其用于服务端开发 并发编程和网络编 程等 1 1 Go语言特性及应用场景 1 容易上手 2 编程速度快 3 原生支持并发
  • golang json性能分析详解

    原文地址 https www jb51 net article 135264 htm json格式可以算我们日常最常用的序列化格式之一了 Go语言作为一个由Google开发 号称互联网的C语言的语言 自然也对JSON格式支持很好 下面这篇文
  • Go单体服务开发最佳实践

    单体最佳实践的由来 对于很多初创公司来说 业务的早期我们更应该关注于业务价值的交付 并且此时用户体量也很小 QPS 也非常低 我们应该使用更简单的技术架构来加速业务价值的交付 此时单体的优势就体现出来了 正如我直播分享时经常提到 我们在使用
  • Go语言学习9-结构体类型

    结构体类型 引言 1 结构体 1 1 类型表示法 1 2 值表示法 1 3 属性和基本操作 附录 引言 书接上篇 我们了解了Go语言的接口类型 现在介绍Go语言的结构体类型 主要如下 1 结构体 结构体类型既可以包含若干个命名元素 又称字段
  • go语言学习 1 -- 类型

    Go语言接受了函数式编程的一些想法 支持匿名函数与闭包 接受了以Erlang语言为代表的面向消息编程思想 支持goroutine和通道 并推荐使用消息而不是共享内存来进行并发编程 总体来说 Go语言是一个非常现代化的语言 精小但非常强大 学

随机推荐

  • JDK8新特性----lambda表达式

    一 Lambda表达式 1 Lambda表达式 注意 函数式接口 接口中只有一个抽象方法 参数1 参数2 抽象方法的参数 gt 分隔符 表示抽象方法的实现 1 lambda基本用法 package com wt practice lx01
  • Java 反射机制(二)

    前言 在上篇 Java 反射机制 一 介绍了一些 Java 反射相关的常用 API 在知道了如何去使用反射之后 作为一个合格的工程师 下一步肯定是要去了解它的如何实现的 我们今天就来看看在 JDK 源码中是如何去实现反射的 PS 以下源码分
  • docker查看mysql日志_如何查看docker运行日志

    查看docker运行日志的方法介绍 docker attach命令 docker attach options 容器会连接到正在运行的容器 然后将容器的标准输入 输出和错误流信息附在本地打印出来 命令中options的取值有三种 detac
  • 护网蓝队(初级)

    护网蓝队 初级 主要是会看各种攻击payload 注意常见的payload 练习各种漏洞的利用方法 学会看利用漏洞的请求长什么样 payload长什么样 payload长什么样 给个请求包 能不能认出来是攻击流量 是的话是什么漏洞的利用 蓝
  • 树09--二叉树的下一个结点

    树09 二叉树的下一个结点 jz57 题目概述 解析 参考答案 注意事项 说明 题目概述 算法说明 给定一个二叉树其中的一个结点 请找出中序遍历顺序的下一个结点并且返回 注意 树中的结点不仅包含左右子结点 同时包含指向父结点的next指针
  • Qt 信号连接多个槽函数 执行顺序

    执行顺序 同一信号连接多个槽呢 槽函数执行没有绝对的先后顺序 如 connect slider QSlider valueChanged spin box QSpinBox setValue connect slider QSlider v
  • 读研期间小论文投稿-个人总结

    我是2014级研究生 学校只是一个普通211 而且工科很弱 导师对我是放养 让我回忆下 上学期就见过她一次 而且她快退休了 没项目没经费没权利 但我觉得跟着她还挺好 因为我可以自己研究自己喜欢的 没人妨碍 但同时导师没有基金 所以我的小论文
  • 两个linux服务器间复制文件

    scp是secure copy的简写 用于在Linux下进行远程拷贝文件的命令 和它类似的命令有cp 不过cp只是在本机进行拷贝不能跨服务器 1 命令格式 scp 参数 原路径 目标路径 2 命令实例 从本地服务器复制到远程服务器 1 复制
  • Vue使用Swiper看这一篇就够了

    Vue使用Swiper看这一篇就够了 此案例实现需求 完成swiper动态异步数据下的slide渲染 自定义分页器样式 解决loop true设置时的事件丢失问题 swiper鼠标移入 移出 暂停 开始轮播 单页面渲染多个swiper组件互
  • 什么是区块链概念

    区块链到底有什么价值 区块链技术被称为价值互联网 大体上原因在于它解决了原有互联网的三个基本问题 第一 区块链通过在数字货币领域的应用 提供了资金流 或者叫资本流 信息在互联网的流动的解决方案 第二 区块链通过加密和分布式账本的引用 解决了
  • 关于Visual Studio 不支持x64 内联汇编分析

    记录一下今天的大坑 实在是有必要记录一下 调程序发现参数在函数传递时 出现了异常的值 已经确认不是指针破坏的问题 用汇编看了下 发现汇编寄存器地址都取错了 在release开启o2优化时出现 关掉又正常 实在是百思不得其解 对于内联汇编 其
  • Mysql根据拼音首字母分组和排序

    最近业务上有个需求 需要根据英文字母展示对应的人名 和我们手机的通讯录差不多 如下图所示 通常如果表设计的时候增加了对应的首字母字段应该很好实现 那如果没加 应该怎么实现呢 图示Sql SELECT name ELT INTERVAL CO
  • Java FileOutputStream类

    文章目录 总结 FileOutputStream类数据结构 FileOutputStream类方法 构造方法 操作方法 总结 FileOutputStream类用于将数据写入文件或文件描述符的输出流 FileOutputStream用于写入
  • 如何查看局域网内所有IP

    要如何查看局域网内正在使用的电脑的IP一共分以下几个步骤 第一步 点击电脑左下角的 开始 然后再点击 运行 第二步 在运行窗口里填入 cmd 然后点击确定 第三步 在cmd命令窗口输入 ipconfig ALL 命令 点击键盘上的回车键 第
  • 2021年字节跳动+京东+美团面试总结!内含福利

    开篇 说一下我大概的情况 渣本毕业 工作已经有快3年了 从高中就开始玩小破站 无论是学习还是日常放松都是在b站 大学主学的软件技术专业 所以 入职bilibili是我大学时期给自己定的小目标 在学校 专业学的算中上的水平 课本知识和老师讲的
  • delphi with do和for do语句

    1 with 对象名 do语句只是为了减少输入的字符 不必每次重复名字 直接写变量 procedure TForm1 Button1Click Sender TObject 正常写法beginedit1 text hello edit1 c
  • J1939协议与CAN2.0对应关系

  • python贪吃蛇小游戏,面向对象设计模式,附带源码以及所需素材

    在python中通过面向对象设计模式来实现一个贪吃蛇小游戏 源码在最下方 上传的资源包内也包括代码源文件以及所需素材等 源文件在game文件夹内 exe文件可直接运行 pygame模块需要自行下载 先来看运行效果图 开始界面 点击按钮开始游
  • Leetcode 括号的分数 -- 栈

    题目描述 leetcode 856 括号的分数 给定一个平衡括号字符串 S 按下述规则计算该字符串的分数 得 1 分 AB 得 A B 分 其中 A 和 B 是平衡括号字符串 A 得 2 A 分 其中 A 是平衡括号字符串 示例 1 输入
  • Go语言学习18-基准测试

    基准测试 引言 基准测试 1 编写基准测试函数 2 计时器 3 内存分配统计 4 基准测试的运行 结语 引言 所谓基准测试 Benchmark Test 简称BMT 是指 通过一些科学的手段实现对一类测试对象的某项性能指标进行可测量 可重复