如何对init()函数进行基准测试

时间:2018-10-31 05:44:45

标签: go

我正在玩下面的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中如何完成?

谢谢。

1 个答案:

答案 0 :(得分:3)

是的,一个包中可以有多个init(),实际上,一个文件中可以有多个init()。可以在here中找到有关init的更多信息。请记住,init()会在程序的main()甚至启动之前自动被调用一次。

基准框架多次运行您的代码(在您的情况下为100000)。这使其可以测量非常短的功能以及非常长的功能。基准测试没有包含init()的时间。您遇到的问题是您不了解基准测试的目的。通过基准测试,您可以比较两个或多个单独的实现,以确定哪个实现更快(也可以根据相同功能的输入来比较性能)。它不会告诉您应该在哪里进行。

您基本上在做什么,就是Premature Optimization。在这里,您开始优化代码,试图使其尽可能快地运行,而又不知道程序实际上将大部分时间花在哪里。 Profiling是衡量程序时间和空间复杂度的过程。在实践中,它使您可以查看程序大部分时间在哪里。使用该信息,您可以编写更有效的功能。可以在此blog post中找到有关在go中进行分析的更多信息。