【问题标题】:Order of the code and performance代码顺序和性能
【发布时间】:2017-05-27 06:55:56
【问题描述】:

我想找出哪个更快:struct vs array。所以我编写了一个 GO 代码,其中我将 4 个 int 值(1、2、3 和 4)写入结构的成员,然后写入长度为 4 的数组。我试图找出写入所需的时间。

案例 1:首先,我将值写入结构,然后写入数组。在这里我发现数组比结构更快。

package main

import (
    "fmt"
    "time"
)

type abc struct {
    a, b, c, d int
}

func main() {

    var obj abc

    t1 := time.Now()
    obj.a = 1
    obj.b = 2
    obj.c = 3
    obj.d = 4
    t2 := time.Since(t1)

    fmt.Println("Struct access time: : ", t2)

    a := make([]int, 4)
    t3 := time.Now()
    a[0] = 1
    a[1] = 2
    a[2] = 3
    a[3] = 4
    t4 := time.Since(t3)

    fmt.Println("Array access time: : ", t4)

}

案例2:其次,我将值写入数组,然后写入结构。在这里我发现结构比数组快。

package main

import (
    "fmt"
    "time"
)

type abc struct {
    a, b, c, d int
}

func main() {

    var obj abc

    a := make([]int, 4)
    t3 := time.Now()
    a[0] = 1
    a[1] = 2
    a[2] = 3
    a[3] = 4
    t4 := time.Since(t3)

    fmt.Println("Array access time: : ", t4)

    t1 := time.Now()
    obj.a = 1
    obj.b = 2
    obj.c = 3
    obj.d = 4
    t2 := time.Since(t1)

    fmt.Println("Struct access time: : ", t2)

}

为什么性能取决于我先写的内容​​?我首先写的那个似乎比较慢。为什么会这样?

【问题讨论】:

    标签: performance go struct slice benchmarking


    【解决方案1】:

    第一次运行任何代码可能会有一些(显着的)开销,例如相关代码可能会被加载,许多事情可能会被推迟到需要时(例如内部缓冲区)。再次运行相同的东西可能需要更少的时间,差异甚至可能是几个数量级

    当你想测量执行时间时,你应该多次运行它,测量多次运行的执行时间,并计算平均时间。出于上述原因,从计算中排除前(一些)运行也是一个好主意。

    在 Go 中,最好和最简单的方法是使用测试文件和基准函数。阅读testing的包文档了解更多细节和示例。

    您的案例可以这样进行基准测试:

    package main
    
    import "testing"
    
    type abc struct {
        a, b, c, d int
    }
    
    func BenchmarkSlice(b *testing.B) {
        a := make([]int, 4)
        for i := 0; i < b.N; i++ {
            a[0] = 1
            a[1] = 2
            a[2] = 3
            a[3] = 4
        }
    }
    
    func BenchmarkStruct(b *testing.B) {
        a := abc{}
        for i := 0; i < b.N; i++ {
            a.a = 1
            a.b = 2
            a.c = 3
            a.d = 4
        }
    }
    

    将其保存到something_test.go 之类的文件中,使用go test -bench . 运行它。输出:

    BenchmarkSlice-4        2000000000           1.24 ns/op
    BenchmarkStruct-4       2000000000           0.31 ns/op
    

    您可以看到使用结构体的速度大约快 4 倍。如果您对基准函数重新排序,您将获得相似(非常接近)的结果。

    【讨论】:

    • 在您的基准测试中,structslice 快。在结论中,你写的正好相反。
    • @icza 我明白你说的。我希望两个代码都运行相同。不是所有指令(数组和结构)都像 STR
      。所以两者必须有相同的执行时间
    • @Jsmith slice 版本还包括处理索引值和潜在的边界检查,而 struct 版本没有。
    • 我刚刚阅读了生成的代码。因为编译器确切地知道切片有多大,所以边界检查被忽略了。实际发生的是,对结构的写入完全消除了,我假设通过死存储消除,而对切片的写入则没有。使结构全局禁用死存储消除并且两者执行完全相同。
    • @Art 我猜你的答案是正确的。您可以将其添加为答案吗?
    【解决方案2】:

    另一个答案解释了时间差异,让我们进入结构与切片。

    如果编译器可以在编译时确定切片足够大,则访问切片和结构的元素将生成相同的代码。当然,实际上,编译器通常不知道切片有多大,并且根据您使用的是结构还是切片,将应用完全不同的优化,因此要衡量性能,您必须查看整体程序及其行为,而不仅仅是一个特定的操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-25
      • 1970-01-01
      • 1970-01-01
      • 2023-02-23
      • 1970-01-01
      • 2011-04-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多