这是我参与「第三届青训营 -后端场」笔记创作活动的的第 4 篇笔记
最近正在做一个网络的项目,需要用一个 rand 函数,而 Go 语言中提供了两种 rand 函数,一种是 math package 里的,另一种是 crypto package 里的,根据网上的信息,math 中的 rand 用时会明显更少,但是具体少多少我希望通过 Benchmark 来测试一下,刚好联想到青训营的课程,做了一个极简版的实践
在 GoLand 中做一个 Benchmark,只需要执行以下几步
- 将 .go 文件以 xxx_test.go 命名
- 将测试函数以
BenchmarkXxx(b *testing.B)命名 - 如果有需要初始化的部分,放到
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/rand | 350.3 ns/op |
| math/rand | 8238 ns/op |
| math/rand(不初始化 seed) | 215.8 ns/op |
可以看出,确实如网上所说,crypto/rand 比 math/rand 慢,但是如果 math/rand 通过读取当前 UNIX 时间来初始化 seed 的话,则比 crypto/rand 慢了太多,不过这个测试并不严谨,因为这其中还包含每次变量初始化的时间,但也能一定程度上反应实际性能。看来在实践中,还是要根据自己的实际情况测试才能得出最优的实现方法,而不能仅仅依靠网上的信息