Go语言range语法性能消耗实验
Go的for循环支持range关键字,对map类型或者slice类型进行遍历,使用range进行遍历可以让代码更简洁,但是range是否产生额外的性能消耗呢?下面通过实验来找答案。
实验代码,测试range循环和for循环,以及结构体循环和指针循环的性能区别(github.com):
package labs04
import "testing"
type BigStruct struct {
C01 int
C02 int
C03 int
C04 int
C05 int
C06 int
C07 int
C08 int
C09 int
C10 int
C11 int
C12 int
C13 int
C14 int
C15 int
C16 int
C17 int
C18 int
C19 int
C20 int
C21 int
C22 int
C23 int
C24 int
C25 int
C26 int
C27 int
C28 int
C29 int
C30 int
}
func Loop1(a []*BigStruct) int {
var n = 0
for i := 0; i < len(a); i++ {
n += a[i].C30
}
return n
}
func Loop2(a []*BigStruct) int {
var n = 0
for _, item := range a {
n += item.C30
}
return n
}
func Loop3(a []BigStruct) int {
var n = 0
for i := 0; i < len(a); i++ {
n += a[i].C30
}
return n
}
func Loop4(a []BigStruct) int {
var n = 0
for _, item := range a {
n += item.C30
}
return n
}
func Benchmark_Loop1(b *testing.B) {
b.StopTimer()
var a = make([]*BigStruct, 1000)
for i := 0; i < len(a); i++ {
a[i] = new(BigStruct)
}
b.StartTimer()
for i := 0; i < b.N; i++ {
Loop1(a)
}
}
func Benchmark_Loop2(b *testing.B) {
b.StopTimer()
var a = make([]*BigStruct, 1000)
for i := 0; i < len(a); i++ {
a[i] = new(BigStruct)
}
b.StartTimer()
for i := 0; i < b.N; i++ {
Loop2(a)
}
}
func Benchmark_Loop3(b *testing.B) {
b.StopTimer()
var a = make([]BigStruct, 1000)
b.StartTimer()
for i := 0; i < b.N; i++ {
Loop3(a)
}
}
func Benchmark_Loop4(b *testing.B) {
b.StopTimer()
var a = make([]BigStruct, 1000)
b.StartTimer()
for i := 0; i < b.N; i++ {
Loop4(a)
}
}
实验结果:
dada-imac:misc dada$ go test -test.bench="." labs04 testing: warning: no tests to run PASS Benchmark_Loop1 2000000 923 ns/op Benchmark_Loop2 2000000 819 ns/op Benchmark_Loop3 2000000 825 ns/op Benchmark_Loop4 100000 26230 ns/op ok labs04 10.640s
结论:对结构体slice的range循环最消耗性能,因为数据要复制。