Go 闭包、匿名函数和普通函数的基准

Go 闭包、匿名函数和普通函数的基准,go,Go,我测试了一些函数,不明白为什么闭包和匿名函数的执行时间不同: package main import ( "fmt" "time" ) func X(p *int) { *p += 1 } func main() { n := 1000000000 t0 := time.Now() for i := 0; i < n; i++ { p := 0 x := func(

我测试了一些函数,不明白为什么闭包和匿名函数的执行时间不同:

package main

import (
    "fmt"
    "time"
)

func X(p *int) {
    *p += 1
}

func main() {
    n := 1000000000
    t0 := time.Now()
    for i := 0; i < n; i++ {
        p := 0
        x := func() {
            p += 1
        }
        x()
    }
    fmt.Printf("Closure: %v\n", time.Since(t0))

    t0 = time.Now()
    for i := 0; i < n; i++ {
        p := 0
        func() {
            p += 1
        }()
    }
    fmt.Printf("Anonymous function: %v\n", time.Since(t0))

    t0 = time.Now()
    for i := 0; i < n; i++ {
        p := 0
        X(&p)
    }
    fmt.Printf("Function: %v\n", time.Since(t0))
    return
}
结果:

558.84667ms

267.847834ms

271.102576ms


如果我将变量的定义移出循环,时间是相等的。

除此之外,一些代码生成和一些优化比其他更容易完成。有关详细信息,请参阅Go gc编译器源代码

$ go version
go version devel +e68ac45172 Fri Jul 20 16:04:01 2018 +0000 linux/amd64
未优化:

$ go test bench_test.go -bench=. -benchmem -gcflags='-N'
goos: linux
goarch: amd64
BenchmarkClosure-4         1    2621664326 ns/op    0 B/op    0 allocs/op
BenchmarkAnonymous-4       1    1995507678 ns/op    0 B/op    0 allocs/op
BenchmarkFunction-4        1    2297303813 ns/op    0 B/op    0 allocs/op
优化:

$ go test bench_test.go -bench=. -benchmem
goos: linux
goarch: amd64
BenchmarkClosure-4         2     585091582 ns/op    0 B/op    0 allocs/op
BenchmarkAnonymous-4       5     287299925 ns/op    0 B/op    0 allocs/op
BenchmarkFunction-4        5     287710165 ns/op    0 B/op    0 allocs/op
台架试验(go):


第一个和第二个示例都是闭包,它们关闭外部作用域中的变量,并且都是匿名函数,函数未命名。此外,还可以尝试使用Go附带的基准测试工具进行基准测试,而不是使用自己的工具,附带的工具制作得非常好。最后一点这种微基准测试很可能会产生不准确的性能数据。如果你将时间除以100000000,每次调用的时间为.27到.56纳秒-你的基准测试基本上什么都不做,你测量的是一些无意义的开销指令。您还应该使用内置的基准测试工具,而不是试图手动计时。十亿个变量分配需要一些时间,这并不奇怪。这也是在优化类中,除非您认真考虑将汇编作为实现路径,否则保存的一两个时钟周期根本不重要,“你最好把你的性能测量和调整工作集中在其他地方。”Adrian bench说results@JimB我对更大的n做了同样的测试。同样的结果。这张长凳也一样。
package main

import "testing"

func X(p *int) {
    *p += 1
}

var N = 1000000000

func BenchmarkClosure(b *testing.B) {
    for n := 0; n < b.N; n++ {
        for i := 0; i < N; i++ {
            p := 0
            x := func() {
                p += 1
            }
            x()
        }
    }
}

func BenchmarkAnonymous(b *testing.B) {
    for n := 0; n < b.N; n++ {
        for i := 0; i < N; i++ {
            p := 0
            func() {
                p += 1
            }()
        }
    }
}

func BenchmarkFunction(b *testing.B) {
    for n := 0; n < b.N; n++ {
        for i := 0; i < N; i++ {
            p := 0
            X(&p)
        }
    }
}