我在Go方面还是个新手,最近有些问题让我感到困惑。
我有一段代码(下面是简化版本),我试图对它进行性能测量。我有两种方法:1)使用测试包进行基准测试 2)手动记录时间
运行基准测试输出结果:
30000 55603 ns/op 这很好,但是……当我运行相同函数的30k次并为每个迭代记录时间时,我得到了这样的输出:
test took 0 ns test took 0 ns ... ~10条记录都一样 test took 1000100 ns test took 0 ns test took 0 ns ... 又是很多零 test took 0 ns test took 1000000 ns test took 0 ns
通过计算,可以发现平均值确实是55603 ns/op,就像基准测试所说的那样。
我说,“好吧,我不太擅长优化性能,也不太懂所有的编译器核心知识,但我猜可能是随机垃圾回收?所以我打开了gc日志,确保它有输出,然后彻底关闭了gc......没有垃圾回收,但我看到了同样的情况——有些迭代需要花费一百万倍的时间(?)。”
99%的可能是我的理解哪里出了问题,也许有人可以指点我正确的方向,或者有人确切知道到底发生了什么?:)
另外,对我来说,小于一纳秒(0 ns)有些惊讶,这似乎太快了,但程序确实提供了计算结果,所以我不知道该怎么想了。
编辑1:回答Kenny Grant的问题:我使用goroutine实现了“值生成器”,以实现“懒惰”,现在我已经将它们删除并简化了代码。问题现在少得多了,但仍然可以重现。 Playground链接:https://play.golang.org/p/UQMgtT4Jrf 有趣的是,在playground上没有出现这种情况,但在我的机器上仍然存在。
编辑2:我在win7 x64上运行Go 1.9
编辑3:感谢回复,现在我知道这段代码在playground上无法正常工作。我会在这里重新发布代码片段,以便我们不会失去它。
我有一段代码(下面是简化版本),我试图对它进行性能测量。我有两种方法:1)使用测试包进行基准测试 2)手动记录时间
运行基准测试输出结果:
30000 55603 ns/op 这很好,但是……当我运行相同函数的30k次并为每个迭代记录时间时,我得到了这样的输出:
test took 0 ns test took 0 ns ... ~10条记录都一样 test took 1000100 ns test took 0 ns test took 0 ns ... 又是很多零 test took 0 ns test took 1000000 ns test took 0 ns
通过计算,可以发现平均值确实是55603 ns/op,就像基准测试所说的那样。
我说,“好吧,我不太擅长优化性能,也不太懂所有的编译器核心知识,但我猜可能是随机垃圾回收?所以我打开了gc日志,确保它有输出,然后彻底关闭了gc......没有垃圾回收,但我看到了同样的情况——有些迭代需要花费一百万倍的时间(?)。”
99%的可能是我的理解哪里出了问题,也许有人可以指点我正确的方向,或者有人确切知道到底发生了什么?:)
另外,对我来说,小于一纳秒(0 ns)有些惊讶,这似乎太快了,但程序确实提供了计算结果,所以我不知道该怎么想了。
编辑1:回答Kenny Grant的问题:我使用goroutine实现了“值生成器”,以实现“懒惰”,现在我已经将它们删除并简化了代码。问题现在少得多了,但仍然可以重现。 Playground链接:https://play.golang.org/p/UQMgtT4Jrf 有趣的是,在playground上没有出现这种情况,但在我的机器上仍然存在。
编辑2:我在win7 x64上运行Go 1.9
编辑3:感谢回复,现在我知道这段代码在playground上无法正常工作。我会在这里重新发布代码片段,以便我们不会失去它。
type PrefType string
var types []PrefType = []PrefType{
"TYPE1", "TYPE2", "TYPE3", "TYPE4", "TYPE5", "TYPE6",
}
func GetKeys(key string) []string {
var result []string
for _, t := range types {
rr := doCalculations(t)
for _, k := range rr {
result = append(result, key + "." + k)
}
}
return result
}
func doCalculations(prefType PrefType) []string {
return []string{ string(prefType) + "something", string(prefType) + "else" }
}
func test() {
start := time.Now()
keysPrioritized := GetKeys("spec_key")
for _, k := range keysPrioritized {
_ = fmt.Sprint(k)
}
fmt.Printf("test took %v ns\n", time.Since(start).Nanoseconds())
}
func main() {
for i := 0; i < 30000; i++ {
test()
}
}
以下是我的机器的输出:
编辑4:我已经在我的Ubuntu 17.04笔记本上尝试过相同的操作,输出合理,没有零和百万。看起来这是编译器/运行时库在Windows上的特定问题。如果有人能在他们的机器上验证这个问题(Win 7/8/10),那就太好了。