我正在玩下面的Go代码,该代码使用查找表来计算人口数:
package population
import (
"fmt"
)
var pc [256]byte
func init(){
for i := range pc {
pc[i] = pc[i/2] + byte(i&1)
}
}
func countPopulation() {
var x uint64 = 65535
populationCount := int(pc[byte(x>>(0*8))] +
pc[byte(x>>(1*8))] +
pc[byte(x>>(2*8))] +
pc[byte(x>>(3*8))] +
pc[byte(x>>(4*8))] +
pc[byte(x>>(5*8))] +
pc[byte(x>>(6*8))] +
pc[byte(x>>(7*8))])
fmt.Printf("Population count: %d\n", populationCount)
}
我编写了以下基准代码来检查上述代码块的性能:
package population
import "testing"
func BenchmarkCountPopulation(b *testing.B) {
for i := 0; i < b.N; i++ {
countPopulation()
}
}
哪个给了我以下结果:
100000 18760 ns/op
PASS
ok gopl.io/ch2 2.055s
然后我将代码从init()
函数移至countPopulation()
函数,如下所示:
func countPopulation() {
var pc [256]byte
for i := range pc {
pc[i] = pc[i/2] + byte(i&1)
}
var x uint64 = 65535
populationCount := int(pc[byte(x>>(0*8))] +
pc[byte(x>>(1*8))] +
pc[byte(x>>(2*8))] +
pc[byte(x>>(3*8))] +
pc[byte(x>>(4*8))] +
pc[byte(x>>(5*8))] +
pc[byte(x>>(6*8))] +
pc[byte(x>>(7*8))])
fmt.Printf("Population count: %d\n", populationCount)
}
并再次运行相同的基准代码,这给了我以下结果:
100000 20565 ns/op
PASS
ok gopl.io/ch2 2.303s
观察两个结果后,很明显init()
函数不在基准函数的范围内。这就是为什么与第二次执行相比,第一次执行基准测试花费更少的时间的原因。
现在我有另一个问题正在寻找答案。
如果我只需要对init()
方法进行基准测试,请考虑一个包中可以包含多个init()
函数。在golang
中如何完成?
谢谢。
答案 0 :(得分:3)
是的,一个包中可以有多个init()
,实际上,一个文件中可以有多个init()
。可以在here中找到有关init的更多信息。请记住,init()
会在程序的main()
甚至启动之前自动被调用一次。
基准框架多次运行您的代码(在您的情况下为100000)。这使其可以测量非常短的功能以及非常长的功能。基准测试没有包含init()
的时间。您遇到的问题是您不了解基准测试的目的。通过基准测试,您可以比较两个或多个单独的实现,以确定哪个实现更快(也可以根据相同功能的输入来比较性能)。它不会告诉您应该在哪里进行。
您基本上在做什么,就是Premature Optimization。在这里,您开始优化代码,试图使其尽可能快地运行,而又不知道程序实际上将大部分时间花在哪里。 Profiling是衡量程序时间和空间复杂度的过程。在实践中,它使您可以查看程序大部分时间在哪里。使用该信息,您可以编写更有效的功能。可以在此blog post中找到有关在go中进行分析的更多信息。