Go语言中对函数进行简单的性能测试

首先我们创建目录名为popcount,在popcount目录下创建名为popcount.go的Go文件。我们将文件所属的package命名为popcount。init函数是对package内部的变量进行初始化。我们构建了四个版本的PopCount,然后对四个版本的函数分别进行性能测试,比较运行时间的差异。

package popcount


var pc [256]byte


func init(){
    for i := range pc {
	pc[i] = pc[i / 2] + byte(i&1)
    }
}


func PopCount(x uint64) uint64 {
    return uint64(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))])
}


func PopCount2(x uint64) uint64 {
    var res uint64
    for i := 0; i < 64; i+=8 {
        res += uint64(pc[byte(x>>i)])
    }
    return res
}


func PopCount3(x uint64) uint64 {
    var res uint64
    for i := 0; i < 64; i++ {
    	res += (x&1)
    }
    return res
}


func PopCount4(x uint64) uint64 {
    var res uint64
    for x != 0 {
	res += 1
	x = x & (x - 1)
    }
    return res
}

pc数组一共有256个元素,分别表示0-255各个数字所包含的非零比特个数。第一个版本的PopCount函数是对64位的非零比特个数直接进行加和。第二个版本是用for循环和预先计算好的pc数组进行加和。第三个版本是利用for循环遍历了64个比特位,计算非零比特数。第四个版本是利用了位运算,每次消去最右边一个非零比特位。这里只包含判断条件的for循环实际上等同于while循环。
然后我们在popcount目录下创建名为popcount_test.go的测试文件。这里测试文件的名字必须符合如下格式“任意合法名_test.go”。接着,我们将性能测试文件的package命名为popcount,和被测试文件一致,导入testing包,编写四个性能测试函数分别测试前述四个函数。性能测试函数的函数名以Benchmark这个单词开头。

package popcount 


import "testing"


func BenchmarkPopCount(b *testing.B) {
    for i := 0; i < b.N; i++ {
        PopCount(0xfedcba9876543210)
    }
}


func BenchmarkPopCount2(b *testing.B) {
    for i := 0; i < b.N; i++ {
        PopCount2(0xfedcba9876543210)
    }
}


func BenchmarkPopCount3(b *testing.B) {
    for i := 0; i < b.N; i++ {
        PopCount3(0xfedcba9876543210)
    }
}


func BenchmarkPopCount4(b *testing.B) {
    for i := 0; i < b.N; i++ {
        PopCount4(0xfedcba9876543210)
    }
}

这里b *testing.B 提供了性能测试所需的几个参数,包括b.N这个整数。

最后我们在该文件夹的命令行中运行

go test -bench=.

-bench后面的字符“.”表示运行所有的测试函数。

稍等,我们就可以得到这样的结果

\golang\ch2\popcount>go test -bench=.
goos: windows
goarch: amd64
BenchmarkPopCount-8     1000000000               0.300 ns/op
BenchmarkPopCount2-8    181161799                6.65 ns/op
BenchmarkPopCount3-8    30758346                38.8 ns/op
BenchmarkPopCount4-8    57693139                20.2 ns/op
PASS
ok     /golang/ch2/popcount    5.906s

上面的结果来自amd64指令集下的Windows系统。每个测试函数名后面的8来自GOMAXPROCS,它指定最大逻辑CPU数量。这与并行性能测试息息相关,但是我们这次测试不重要。每个测试函数名后面的第一个数字表示运行次数。第一个测试函数运行了1,000,000,000次,其他函数类似。第三列表示每次运行的耗时,第一个函数每次运行耗时0.3ns,其他函数类似。总共测试时间是5.906s。

测试结果表明(预计算的数组+直接加和的性能)>(预计算的数组+for循环的性能)>(while循环每个非零比特位的性能)>(for循环每一位的性能)。这恰好和“凡事预测立,不预则废”(《礼记》)相符。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值