golang slice for/range遍历性能测试

140 阅读3分钟

很多人做的测试表明,for的性能强于range,真的如此吗? 亲自做个测试。

三种遍历方式

func InSlice[T comparable](a T, s []T) bool {  
    for _, i := range s {  
        if a == i {  
            return true  
        }  
    }  
    return false  
}  

func InSlice1[T comparable](a T, s []T) bool {  
    for k, _ := range s {  
        if a == s[k] {  
            return true  
        }  
    }  
    return false  
}  

func InSlice2[T comparable](a T, s []T) bool {  
    l := len(s)  

    for i := 1; i < l; i++ {  
        if a == s[i] {  
            return true  
        }  
    }  
    return false  
}

测试开始

// go test -bench='BenchmarkInSlice$' -count=10 .  
// goos: darwin  
// goarch: arm64  
// pkg: github.com/lizongying/go-utils  
// BenchmarkInSlice-10 5 207184892 ns/op  
// BenchmarkInSlice-10 5 210529525 ns/op  
// BenchmarkInSlice-10 5 204624450 ns/op  
// BenchmarkInSlice-10 5 205362650 ns/op  
// BenchmarkInSlice-10 5 203210925 ns/op  
// BenchmarkInSlice-10 5 204164450 ns/op  
// BenchmarkInSlice-10 5 201273425 ns/op  
// BenchmarkInSlice-10 5 208560850 ns/op  
// BenchmarkInSlice-10 5 207711300 ns/op  
// BenchmarkInSlice-10 5 206910067 ns/op  
// PASS  
// ok github.com/lizongying/go-utils 22.205s  
func BenchmarkInSlice(b *testing.B) {  
    for n := 0; n < b.N; n++ {  
        var a []int  
        for i := 1; i < 100000000; i++ {  
            a = append(a, i)  
        }  
        InSlice(100000000, a)  
    }  
}  

// go test -bench='BenchmarkInSlice1' -count=10 .  
// goos: darwin  
// goarch: arm64  
// pkg: github.com/lizongying/go-utils  
// BenchmarkInSlice1-10 5 206318867 ns/op  
// BenchmarkInSlice1-10 5 207953442 ns/op  
// BenchmarkInSlice1-10 5 207148500 ns/op  
// BenchmarkInSlice1-10 5 214083775 ns/op  
// BenchmarkInSlice1-10 5 211576917 ns/op  
// BenchmarkInSlice1-10 5 225982375 ns/op  
// BenchmarkInSlice1-10 5 231619367 ns/op  
// BenchmarkInSlice1-10 5 207295975 ns/op  
// BenchmarkInSlice1-10 5 213262542 ns/op  
// BenchmarkInSlice1-10 5 214848125 ns/op  
// PASS  
// ok github.com/lizongying/go-utils 23.100s  
func BenchmarkInSlice1(b *testing.B) {  
    for n := 0; n < b.N; n++ {  
        var a []int  
        for i := 1; i < 100000000; i++ {  
            a = append(a, i)  
        }  
        InSlice1(100000000, a)  
    }  
}  

// go test -bench='BenchmarkInSlice2' -count=10 .  
// goos: darwin  
// goarch: arm64  
// pkg: github.com/lizongying/go-utils  
// BenchmarkInSlice2-10 5 204758850 ns/op  
// BenchmarkInSlice2-10 5 203728883 ns/op  
// BenchmarkInSlice2-10 5 201642900 ns/op  
// BenchmarkInSlice2-10 5 207764067 ns/op  
// BenchmarkInSlice2-10 5 206985317 ns/op  
// BenchmarkInSlice2-10 5 206063683 ns/op  
// BenchmarkInSlice2-10 5 203198800 ns/op  
// BenchmarkInSlice2-10 5 202168783 ns/op  
// BenchmarkInSlice2-10 5 208278617 ns/op  
// BenchmarkInSlice2-10 5 201505567 ns/op  
// PASS  
// ok github.com/lizongying/go-utils 22.244s  
func BenchmarkInSlice2(b *testing.B) {  
    for n := 0; n < b.N; n++ {  
        var a []int  
        for i := 1; i < 100000000; i++ {  
            a = append(a, i)  
        }  
        InSlice2(100000000, a)  
    }  
}

这是一个真实场景,结论是range性能更好,多次测试结果一致。 为什么有区别呢?

1.本例子中1和3相比:range忽略了index,实际上index在大多是场景下也是非必要的。range不需要计算长度 2.本例子中1和2相比:1不用根据index再获取值 3.本例子中2确实不如3

所以在通常场景下,如果不需要获取index,range还方便,为什么不用呢? 当然,当元素比较大非指针的情况下,range可能不如for,暂未测试。