您的位置 首页 golang

Golang笔记-基准测试

上一篇写了些简单的单元测试,这一篇来看看go中的基准测试。在go中基准测试也是开箱即用的。使用testing.B结构对象。

需要测试的代码

我们依然用上一篇的代码结构

│  main.go│  main_test.gomain.gofunc JoinStrUseSprint(a,b string) string {    return  fmt.Sprintf("%s%s",a,b)}func JoinStrUseNor(a,b string) string {    return  a+b}

创建一个基准测试

创建普通单元测试我们使用TestFunc来定义。创建基准测试我们需要使用BenchmarkFunc来定义。

func TestJoinStrUseNor(t *testing.T) {    s := JoinStrUseNor("aaa","bbb")    t.Log(s)}func TestJoinStrUseSprint(t *testing.T) {    s := JoinStrUseSprint("aaa","bbb")    t.Log(s)}func BenchmarkJoinStrUseNor(b *testing.B) {    b.ResetTimer()    for i:=0; i<b.N; i++{        JoinStrUseNor("aaa","bbb")    }}func BenchmarkJoinStrUseSprint(b *testing.B) {    b.ResetTimer()    for i:=0; i<b.N; i++{        JoinStrUseSprint("aaa","bbb")    }}

执行基础测试

go test -bench=. -benchtime=1s -benchmem -count=1goos: linuxgoarch: amd64pkg: testBenchmarkJoinStrUseNor-8        79888155                15.5 ns/op             0 B/op          0 allocs/opBenchmarkJoinStrUseSprint-8      8956500               135 ns/op              40 B/op          3 allocs/opPASSok      test    2.930s
命令参数
  • -bench=. 表示指定执行测试函数。.表示执行所有,如果修改为go test -bench=BenchmarkJoinStrUseSprint那么只会执行BenchmarkJoinStrUseSprint
  • -benchtime=1s指定执行时间为1s
  • -benchmem显示内存情况
  • -count=1表示执行一次
响应参数
  • goos: linux 操作系统
  • goarch: amd64 系统体系架构
  • BenchmarkJoinStrUseNor-8 执行的函数名称以及对应的GOMAXPROCS值。
  • 79888155 b.N的值
  • 15.5 ns/op 执行一次函数所花费的时间
  • 0 B/op 执行一次函数分配的内存
  • 0 allocs/op 执行一次函数所分配的内存次数

结果分析

通过上面的响应结果参数,我们很容易得出拼接两个字符串直接用+号连接,比使用fmt.Sprintf()的性能高。

样本分析

有时候因为一些因素的影响,我们单次测试的结果可能不准备,这个时候我们就需要进行多次测试比如go test -bench=BenchmarkJoinStrUseSprint -benchtime=1s -benchmem -count=10将测试的次数定义为10 或者更大,这个时候我就需要去分析这些结果得到相对正确的测试结果。但是这个时候时候如果我们人工去分析,工作量无疑是很大的,而且很困难。这个时候我们就可以借助一个工具 benchstat

benchstatGolang官方推荐的一款命令行工具,可以针对一组或多组样本进行分析,如果同时分析两组样本(比如优化前和优化后),还可以给出性能变化结果。

安装

go get golang.org/x/perf/cmd/benchstat

分析

  • 为了对比我们增加一个函数
func JoinStrOpt(a,b string) string {    return  fmt.Sprintf("%s%s",a,b)}
  • 增加测试
func BenchmarkJoinStrOpt(b *testing.B) {    b.ResetTimer()    for i:=0; i<b.N; i++{        JoinStrOpt("aaa","bbb")    }}
  • 执行测试并保存测试结果到before.txt
go test -bench=BenchmarkJoinStrOpt -benchmem -count=10 | tee before.txtgoos: linuxgoarch: amd64pkg: testBenchmarkJoinStrOpt-8            9143092               131 ns/op              40 B/op          3 allocs/opBenchmarkJoinStrOpt-8            9222475               131 ns/op              40 B/op          3 allocs/opBenchmarkJoinStrOpt-8            9344643               130 ns/op              40 B/op          3 allocs/opBenchmarkJoinStrOpt-8            9127231               131 ns/op              40 B/op          3 allocs/opBenchmarkJoinStrOpt-8            9223482               130 ns/op              40 B/op          3 allocs/opBenchmarkJoinStrOpt-8            9126334               131 ns/op              40 B/op          3 allocs/opBenchmarkJoinStrOpt-8            9364201               129 ns/op              40 B/op          3 allocs/opBenchmarkJoinStrOpt-8            9248034               130 ns/op              40 B/op          3 allocs/opBenchmarkJoinStrOpt-8            9034518               130 ns/op              40 B/op          3 allocs/opBenchmarkJoinStrOpt-8            9102846               130 ns/op              40 B/op          3 allocs/opPASSok      test    13.323s
  • 简单分析结果
benchstat before.txtname          time/opJoinStrOpt-8  130ns ± 1%name          alloc/opJoinStrOpt-8  40.0B ± 0%name          allocs/opJoinStrOpt-8   3.00 ± 0%

可以看出benchstrat会给我一个执行10测试的结果分析,平均数值以及波动数值。

对比分析

  • 修改代码为直接相加两个字符串既JoinStrUseNor的内容
func JoinStrOpt(a,b string) string {    return  a+b}
  • 再次执行测试并保存结果到after.txt
>go test -bench=BenchmarkJoinStrOpt -benchmem -count=10 | tee after.txtgoos: linuxgoarch: amd64pkg: testBenchmarkJoinStrOpt-8           78033046                15.3 ns/op             0 B/op          0 allocs/opBenchmarkJoinStrOpt-8           77211630                15.3 ns/op             0 B/op          0 allocs/opBenchmarkJoinStrOpt-8           78088903                15.4 ns/op             0 B/op          0 allocs/opBenchmarkJoinStrOpt-8           77907912                15.3 ns/op             0 B/op          0 allocs/opBenchmarkJoinStrOpt-8           73805730                15.3 ns/op             0 B/op          0 allocs/opBenchmarkJoinStrOpt-8           78508854                15.3 ns/op             0 B/op          0 allocs/opBenchmarkJoinStrOpt-8           73493384                15.2 ns/op             0 B/op          0 allocs/opBenchmarkJoinStrOpt-8           78618926                15.2 ns/op             0 B/op          0 allocs/opBenchmarkJoinStrOpt-8           74973290                15.2 ns/op             0 B/op          0 allocs/opBenchmarkJoinStrOpt-8           79287993                15.4 ns/op             0 B/op          0 allocs/opPASSok      test    11.959s
  • 对比分析
>benchstat before.txt after.txtname          old time/op    new time/op    deltaJoinStrOpt-8     130ns ± 1%      15ns ± 1%   -88.27%  (p=0.000 n=10+10)name          old alloc/op   new alloc/op   deltaJoinStrOpt-8     40.0B ± 0%      0.0B       -100.00%  (p=0.000 n=10+10)name          old allocs/op  new allocs/op  deltaJoinStrOpt-8      3.00 ± 0%      0.00       -100.00%  (p=0.000 n=10+10)

可以看到benchstat会给我直观的展示出优化代码前后的优化差值。

对比值括号中的数据含义

p表示结果的可信程度,p 值越大可信程度越低,统计学中通常把p=0.05做为临界值,超过此值说明结果不可信,可能是样本过少等原因。

n=10+10表示采用的样本数,,就跟投票一样通常会去掉一个最高分,一个最低分。出于某些原因(比如数据值反常,过大或过小),benchstat会舍弃某些样本,本例中优化前,优化后的数据没有舍弃所以是10+10.

参考资料

期待与您一起交流
白色底可爱幼稚微信公众号底部二维码.png


文章来源:智云一二三科技

文章标题:Golang笔记-基准测试

文章地址:https://www.zhihuclub.com/588.shtml

关于作者: 智云科技

热门文章

网站地图