Go 语言 Benchmark 极简实践(以 rand.Read() 为例) | 青训营笔记

479 阅读2分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第 4 篇笔记

最近正在做一个网络的项目,需要用一个 rand 函数,而 Go 语言中提供了两种 rand 函数,一种是 math package 里的,另一种是 crypto package 里的,根据网上的信息,math 中的 rand 用时会明显更少,但是具体少多少我希望通过 Benchmark 来测试一下,刚好联想到青训营的课程,做了一个极简版的实践

在 GoLand 中做一个 Benchmark,只需要执行以下几步

  1. 将 .go 文件以 xxx_test.go 命名
  2. 将测试函数以BenchmarkXxx(b *testing.B)命名
  3. 如果有需要初始化的部分,放到func TestMain(m *testing.M)中,这里并不涉及到初始化

函数内部需要有一个 for 循环,这里测试随机生成一个 256B 比特流的速度

func BenchmarkRand(b *testing.B) {
   for n := 0; n < b.N; n++ {
      var a = make([]byte, 256)
      rand.Read(a)
   }
}

这里在调用rand.Read()的时候使用的是 crypto/rand,需要注意的是 crypto/rand 使用了算法来保证每回生成的结果都是“随机”的,因此在调用 math/rand 时应当加上初始化 seed 的语句:

func BenchmarkRand(b *testing.B) {
   for n := 0; n < b.N; n++ {
      var a = make([]byte, 256)
      rand.Seed(time.Now().UnixNano())
      rand.Read(a)
   }
}

按照上述步骤编写完成后,GoLand 会在 Benchmark 函数边上自动生成一个绿色的三角,直接点就可以开始测试了(JetBrains yyds),如果通过命令行的话,则需要输入

go test -bench=BenchmarkRand

测试结果

函数执行速度
crypto/rand350.3 ns/op
math/rand8238 ns/op
math/rand(不初始化 seed)215.8 ns/op

可以看出,确实如网上所说,crypto/rand 比 math/rand 慢,但是如果 math/rand 通过读取当前 UNIX 时间来初始化 seed 的话,则比 crypto/rand 慢了太多,不过这个测试并不严谨,因为这其中还包含每次变量初始化的时间,但也能一定程度上反应实际性能。看来在实践中,还是要根据自己的实际情况测试才能得出最优的实现方法,而不能仅仅依靠网上的信息