或者根据阵列大小突然减速

时间:2014-02-10 18:02:20

标签: arrays go benchmarking

我编写了一个简单的程序,该程序对包含在一个巨大的切片中的所有值进行OR运算。当我使用10倍大的切片时,我预计会有10倍的性能下降。但是,在执行提供的测试时,存在巨大的性能差距。程序输出如下:

oadam@oadam-Latitude-E6510:~/$ go test -bench .
testing: warning: no tests to run
PASS
BenchmarkLittle 2000000000           0.11 ns/op
BenchmarkBig           1    2417869962 ns/op
ok      _/home/oadam/   5.048s

代码

package main

import (
    "math/rand"
    "testing"
)

const (
    little = 5000000
    big    = 50000000
)

var a = make([]uint32, big)

func benchOR(b *testing.B, l int) {
    for i := 0; i < l; i++ {
        a[i] = rand.Uint32()
    }

    var result uint32
    for i := 0; i < l; i++ {
        result |= a[i]
    }
}

func BenchmarkLittle(b *testing.B) {
    benchOR(b, little)
}

func BenchmarkBig(b *testing.B) {
    benchOR(b, big)
}
编辑:必须是go test -bench中的错误。使用手动计时我不会重现

package main

import (
    "log"
    "math/rand"
    "time"
)

const (
    little = 5000000
    big    = 50000000
)

var a = make([]uint32, big)

func initA(l int) {
    for i := 0; i < l; i++ {
        a[i] = rand.Uint32()
    }
}

func test(l int) uint32 {
    var result uint32
    for i := 0; i < l; i++ {
        result |= a[i]
    }
    return result
}

func main() {
    initA(little)
    var before = time.Now()
    test(little)
    log.Println(time.Since(before))

    initA(big)
    var before2 = time.Now()
    test(big)
    log.Println(time.Since(before2))

}

2 个答案:

答案 0 :(得分:5)

问题在于您没有使用b.N,它会告诉您运行基准测试的次数。此外,如果您只想对ORing进行基准测试,您可能只需要初始化一次数组,或者至少调用b.ResetTimer(),这样就不会计算初始化。

这是我最终得到的结果,它给出了预期的结果:

package main

import (
    "math/rand"
    "testing"
)

const (
    little = 5000000
    big    = 50000000
)

var a = make([]uint32, big)

func init() {
    for i := 0; i < big; i++ {
        a[i] = rand.Uint32()
    }
}

func benchOR(b *testing.B, l int) {
    var result uint32
    for _, u := range a[:l] {
        result |= u
    }
}

func BenchmarkLittle(b *testing.B) {
    for i := 0; i < b.N; i++ {
        benchOR(b, little)
    }
}

func BenchmarkBig(b *testing.B) {
    for i := 0; i < b.N; i++ {
        benchOR(b, big)
    }
}

我的结果:

BenchmarkLittle      500       3222064 ns/op
BenchmarkBig          50      32268023 ns/op

答案 1 :(得分:2)

我不认为这是一个错误。我修改了你的代码,这就是我得到的:

% go test -bench=.
testing: warning: no tests to run
PASS
BenchmarkLittle 2000000000           0.00 ns/op
BenchmarkBig  2000000000           0.02 ns/op
ok    _/Users/kavu/TMP/becnh_or 12.659s

代码:

    package main

    import (
        "math/rand"
        "testing"
    )

    const (
        little = 5000000
        big    = 50000000
    )

    func benchOR(a []uint32, l int) (result uint32) {
        for i := 0; i < l; i++ {
            result |= a[i]
        }
        return result
    }

    func BenchmarkLittle(b *testing.B) {
        var a = make([]uint32, big)

        for i := 0; i < little; i++ {
            a[i] = rand.Uint32()
        }

        b.ResetTimer()
        benchOR(a, little)
    }

    func BenchmarkBig(b *testing.B) {
        var a = make([]uint32, big)

        for i := 0; i < big; i++ {
            a[i] = rand.Uint32()
        }

        b.ResetTimer()
        benchOR(a, big)
    }

您可以对b.ResetTimer()benchOR(a, big)内容进行评论,看看会发生什么。您也可以尝试big常量。某处10000000它足够快,即使没有重置计时器也是如此。因此,使用rand.Uint32生成一个大切片会减慢所有内容。