首页 > 其他分享 >Go 语言基准测试入门

Go 语言基准测试入门

时间:2024-10-14 21:19:57浏览次数:8  
标签:入门 基准 内存 测试 Go 性能 op

之前在写 Java 的文章的时候,如果想在本地进行某段代码的性能测试(通常是对比另外一段或者几段),就会用到基准测试框架 JMH ,也的确非常好用。虽然我学习 Go 语言有一段时间了,对于基准测试还没有涉猎,下面就分享Go 语言的基准测试入门实践。

什么是基准测试

基准测试(Benchmarking)是一种通过执行预定任务来测量系统或代码性能的测试方法,主要目的是评估软件在特定负载和条件下的表现,常常关注运行时间、内存消耗、吞吐量和延迟等指标。在开发过程中,基准测试用于量化代码的性能差异,帮助开发者识别性能瓶颈并为优化提供有力的数据支持。

它的主要用途在于评估性能、监测性能回归、指导优化以及比较不同技术或方案。通过基准测试,开发者可以准确了解不同实现方案的性能表现,确保优化过程中不会引入性能退化的问题,确保代码在实际场景下的表现符合预期。基准测试的结果为找到性能瓶颈提供了数据依据,避免盲目优化的风险。

在性能优化中,基准测试的作用尤为重要。它不仅能提供清晰的定量分析,让优化决策基于真实的数据,而非直觉或经验,还能帮助快速发现代码中的性能瓶颈,如某个函数或 I/O 操作的效率低下。此外,基准测试也可以验证优化后的效果,通过对比前后的数据,判断所做的更改是否真正提升了性能。同时,基准测试还可以融入到持续集成和持续交付的流程中,确保系统在长期演进中的性能稳定性。

Go 语言的基准测试

Go 语言的基准测试用于评估代码的性能表现,尤其是函数和操作的执行时间。它通过多次运行相同的代码片段,计算平均耗时,提供准确的测试结果。基准测试常用于比较不同实现方案、验证优化效果,确保代码在不同场景下的效率,并能够检测性能回归。

此外,Go 的基准测试支持设置不同的输入条件,模拟实际负载,帮助开发者全面评估代码性能。它还能追踪内存分配情况,发现潜在的内存问题。基准测试生成的报告为优化提供了有力的数据支持,使开发者能更有效地识别瓶颈并进行改进。

testing.B 是 Go 语言中的一个结构体,用于基准测试,专门用于测量代码的性能。它提供了执行基准测试的必要工具,例如控制测试运行的次数、记录执行时间、追踪内存分配等。在使用 testing.B 进行基准测试时,Go 会自动多次运行测试代码,以确保结果的稳定性和准确性,帮助开发者准确评估代码的性能表现并发现优化机会。

基准测试实践

编写规范

在开始之前,我们先来看看 Go 语言的基准测试用例编写过程中,需要遵循的一些规范。在 Go 语言中,编写基准测试时遵循一定的规范是非常重要的,这有助于确保测试的准确性、可读性和可维护性。以下是一些基准测试编写的基本规范:

  1. 命名规范:基准测试函数应以 Benchmark 开头,后跟被测试功能的描述。命名应清晰明了,以便他人理解其测试的内容。例如:BenchmarkFunctionName
  2. 使用 testing.B:基准测试的参数必须是 *testing.B 类型,利用其提供的方法来执行性能测试。
  3. 循环测试:在基准测试中,使用 b.N 来控制循环次数,确保基准测试运行足够多次,以获取稳定的性能数据。b.N 的值由 Go 的测试框架自动管理,以避免人为干预。
  4. 避免副作用:基准测试应避免具有副作用的操作,确保每次运行的结果不受外部因素影响。确保测试函数中的代码是可重复执行的。
  5. 资源清理:如果基准测试中使用了需要清理的资源(如文件、网络连接等),应在测试结束后确保资源得到妥善处理,尽量使用 defer 语句来保证清理操作的执行。

代码实践

下面我通过一些简单的例子展示 Go 语言基准测试的 code,我用了两种字符串拼接的方法来演示。

package test  
  
import (  
    "strings"  
    "testing")  
  
// 基准测试示例:测试使用 + 运算符连接字符串的性能  
func BenchmarkStringConcat(b *testing.B) {  
    setConfig(b)  
    str1 := "Hello"  
    str2 := "FunTester"  
    for i := 0; i < b.N; i++ {  
       _ = str1 + str2  
    }  
}  
  
// 基准测试示例:测试使用 strings.Builder 连接字符串的性能  
func BenchmarkStringBuilder(b *testing.B) {  
    setConfig(b)  
    str1 := "Hello"  
    str2 := "FunTester"  
    for i := 0; i < b.N; i++ {  
       var builder strings.Builder  
       builder.WriteString(str1)  
       builder.WriteString(str2)  
       _ = builder.String()  
    }  
}  
  
func setConfig(b *testing.B) {  
    b.SetParallelism(4) // 设置并行测试的 goroutine 数量  
    b.ReportAllocs()    // 开启内存分配跟踪  
    b.SetBytes(1024)    // 设置每次操作处理的字节数  
}

我们可以直接在 IDE 中执行,也可以通过以下命令行执行 benchmark 基准测试。

go test -bench . -cpu 1,2,4,8,12

控制台输出:

goos: darwin
goarch: arm64
pkg: tempProject/test
BenchmarkStringConcat-2         100000000               11.61 ns/op     88166.09 MB/s          0 B/op          0 allocs/op
BenchmarkStringConcat-4         100000000               11.71 ns/op     87425.82 MB/s          0 B/op          0 allocs/op
BenchmarkStringConcat-8         100000000               11.62 ns/op     88098.01 MB/s          0 B/op          0 allocs/op
BenchmarkStringBuilder-2        34372545                33.96 ns/op     30155.42 MB/s         24 B/op          2 allocs/op
BenchmarkStringBuilder-4        35140291                33.75 ns/op     30341.89 MB/s         24 B/op          2 allocs/op
BenchmarkStringBuilder-8        34851384                33.99 ns/op     30129.57 MB/s         24 B/op          2 allocs/op
PASS
ok      tempProject/test        7.951s

测试报告解读

测试报告的解读可以从以下几个方面进行分析:

环境信息:

  • goos: darwin:表示操作系统是 macOS(Darwin 是 macOS 的核心)。
  • goarch: arm64:表示运行的架构是 ARM64(常见于苹果的 M1 和 M2 芯片)。
  • pkg: tempProject/test:表示基准测试运行在 tempProject/test 包中。

基准测试结果:

每一行结果的格式如下:

BenchmarkName-N         总运行次数               平均耗时           吞吐量            内存使用          内存分配次数

基准测试:

  • BenchmarkStringConcat-2:使用 + 运算符连接字符串,运行 100,000,000 次,平均耗时 11.61 ns/op,吞吐量 88166.09 MB/s,内存使用 0 B/op,内存分配次数 0 allocs/op。
  • BenchmarkStringConcat-4:相似的性能,平均耗时 11.71 ns/op,吞吐量稍低 87425.82 MB/s。
  • BenchmarkStringConcat-8:表现相近,平均耗时 11.62 ns/op,吞吐量 88098.01 MB/s。

测试结论

  • 性能对比:BenchmarkStringConcat 的性能明显优于 BenchmarkStringBuilder,适合用于简单字符串连接的场景。
  • 内存管理:BenchmarkStringConcat 没有进行任何内存分配,而 BenchmarkStringBuilder 则有一定的内存使用和分配次数,显示出在性能敏感的环境中,选择合适的字符串连接方式至关重要。
  • 测试时长:整个测试运行的时间为 7.951s,这个时间在基准测试中是合理的,表明测试的复杂度和工作量适中。

通过以上测试,可以帮助我们在实际项目中选择合适的字符串操作方式,以优化性能和内存使用。

testing.B 常用 API

在 Go 语言的基准测试中,*testing.B 提供了一系列常用的 API,帮助我们进行高效的性能测试和评估。以下是一些常用的 *testing.B 方法及其功能:

  1. b.N:这是一个整数值,表示基准测试要执行的循环次数。开发者在基准测试中通常使用 b.N 来控制代码的执行次数,以获取稳定的性能数据。
  2. b.ResetTimer():在基准测试中,可以调用此方法重置计时器。这在需要进行一些初始化操作后,确保不将这些操作的时间计入基准测试时非常有用。
  3. b.StopTimer():此方法用于停止基准测试的计时。可以在测试中使用此方法来排除某些不需要计入测试时间的操作,例如初始化或清理操作。
  4. b.StartTimer():用于重新启动计时器。当需要停止计时并进行某些不希望计入测试的操作后,可以通过此方法恢复计时。
  5. b.ReportAllocs():调用此方法可以在基准测试结束时报告内存分配情况。如果希望监测内存的使用情况,可以在基准测试开始时调用此方法。
  6. b.Log(args ...interface{}):该方法允许开发者在基准测试中记录信息,类似于 fmt.Println。它可以用于调试或输出测试过程中获取的某些特定数据。
  7. b.SetBytes(n int64):此方法用于设置测试中处理的数据大小,以便在报告中显示吞吐量时提供更准确的信息。通常用于计算每个操作处理的字节数。
  8. b.Run(name string, f func(b *B)):这个方法允许在基准测试中运行子基准测试。这样可以组织复杂的基准测试结构,同时提供更好的结果分析。

通过合理利用这些 API,开发者可以更灵活、高效地编写基准测试,从而准确评估和优化代码性能。

标签:入门,基准,内存,测试,Go,性能,op
From: https://blog.51cto.com/FunTester/12249459

相关文章

  • 基础架构补全—C语言基础入门篇(二)
    前言:    上一篇博客我仅简单对C语言语法基础进行了简单介绍,这次我将对其中遗漏知识进行补全及延申,但冰冻三尺非一日之寒,现在我也只不过是站在C语言的光辉大门前罢了,尚没有彻底迈出一步,希望各位能共励共勉,在接下来的学习中都能,鹏程发韧,培风图南,日进一卒,功不唐捐!1.注释......
  • qt入门介绍
    一、Qt简介Qt是一个基于C++的图形用户界面(GUI)框架,可以开发可视化人机交互程序,但是这并不是Qt的全部。Qt除了可以绘制漂亮的界面外,还包含很多其他的功能:多线程、数据库、图像处理、音视频处理、网络通信、文件IO等。二.Qt优势跨平台:一次编程,到处编译。面向对象开发丰......
  • ui入门
    一、QWidget类     QWidget是Qt中所有用户界面对象的基类,即可视化组件和窗口的基类都是此类,因此QWidget类内部包含了大量的与UI相关的基础特性。最最基础的属性:width:constint宽度,单位像素,不计算边框。属性在文档中通常包含Accessfunctions表示此......
  • Google Play上架对于代理IP地址的选择和要求
    在移动应用的开发和发布过程中,GooglePlay作为主要的应用分发平台,吸引了众多开发者的关注。然而,随着市场竞争的加剧和上架审核机制的严格化,许多开发者开始关注在上架过程中使用代理IP地址的策略。本文将探讨GooglePlay上架对代理IP地址的要求,并提供一些建议。一、代理IP地址......
  • 从0-1入门Flink全网最全吐血总结
    Flink是Apache基金会旗下的一个开源大数据处理框架。目前,Flink已经成为各大公司大数据实时处理的发力重点,特别是国内以阿里为代表的一众互联网大厂都在全力投入,为Flink社区贡献了大量源码。如今Flink已被很多人认为是大数据实时处理的方向和未来,许多公司也都在招聘和......
  • 网络安全学习路线及各类杂项汇总,零基础入门到精通,收藏这篇就够了
    1.安全法(笔者认为学习网络安全前首先得学这个)不是这个↑网络安全法律:了解网络安全相关的法律法规和伦理标准。合规性与标准:学习ISO27001、GDPR等安全标准和合规要求。2.基础知识计算机网络基础:了解网络的基本原理,如TCP/IP协议、OSI模型、路由和交换等。操作系......
  • 盘点IT江湖上能打的十本证书,零基础入门到精通,收藏这一篇就够了
    HCIE考证研究所|厂商认证考试追踪作为一名IT人员,谁没考几个证?值得考的证书都拥有以下特性:▶获政府、企业和从业者认可▶持证人数多,业内共识度高▶帮持证者加分,快速提薪今天,咱们就一起来盘盘,IT行业中,具体哪些认证的含金量高。01系统网络方向认证01华为认证华......
  • (转)探索 Go 语言的内建函数 recover
    原文:https://blog.csdn.net/qq_35240081/article/details/140758441在Go语言中,recover是一个内建函数,用于从panic状态中恢复执行。recover只能在延迟函数(defer)中使用,如果没有panic被触发,recover返回nil。本文将详细介绍recover函数的使用场景和示例。recover函数的......
  • 代码江湖:快问快答 -【Golang】
    Golang筑基期1.Go语言的应用场景和优势有哪些?2.Go的数据类型有哪些?如何声明变量?3.如何定义和使用函数?支持哪些参数和返回值类型?4.什么是数组和切片?它们之间有什么区别?5.Go中的map是什么?如何创建和使用map?6.如何使用控制结构(if、for、switch)进行流程控制?7.什......
  • POLIR-Goverment-Taxation:税收-Receipt:发票-真伪查询:https://inv-veri.chinatax.go
    1.查询网址:https://inv-veri.chinatax.gov.cn/发票代码:旧版发票上有发票代码,一并输入。普票,只需要输入发票号码开票日期开具金额(不含税)验证码增值税专用发票,同上图示:......