代码顺序和性能
Order of the code and performance
我想找出哪个更快:结构与数组。所以我写了一个 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)
}
为什么性能取决于我先写什么?我第一个写的那个似乎比较慢。为什么会这样?
运行 任何第一次编写的代码都可能有一些(显着的)开销,例如可能会加载相关代码,许多事情可能会推迟到需要时才进行(例如内部缓冲区)。 运行 再次做同样的事情可能会花费更少的时间,差异甚至可能是 几个数量级。
每当你想测量执行时间时,你应该运行多次,测量多次运行s的执行时间,并计算平均时间。出于上述原因,从计算中排除第一个(某些)运行 也是一个好主意。
在 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 倍 快。如果您重新排序基准函数,您将获得相似(非常接近)的结果。
另一个答案解释了时间差异,让我们进入结构与切片。
如果编译器可以在编译时确定切片足够大,那么访问切片和结构的元素将生成相同的代码。当然,在现实中,编译器通常不知道切片有多大,并且会根据您使用的是结构还是切片来应用完全不同的优化,因此为了衡量性能,您必须查看整体程序及其行为,而不仅仅是一个特定的操作。
我想找出哪个更快:结构与数组。所以我写了一个 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)
}
为什么性能取决于我先写什么?我第一个写的那个似乎比较慢。为什么会这样?
运行 任何第一次编写的代码都可能有一些(显着的)开销,例如可能会加载相关代码,许多事情可能会推迟到需要时才进行(例如内部缓冲区)。 运行 再次做同样的事情可能会花费更少的时间,差异甚至可能是 几个数量级。
每当你想测量执行时间时,你应该运行多次,测量多次运行s的执行时间,并计算平均时间。出于上述原因,从计算中排除第一个(某些)运行 也是一个好主意。
在 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 倍 快。如果您重新排序基准函数,您将获得相似(非常接近)的结果。
另一个答案解释了时间差异,让我们进入结构与切片。
如果编译器可以在编译时确定切片足够大,那么访问切片和结构的元素将生成相同的代码。当然,在现实中,编译器通常不知道切片有多大,并且会根据您使用的是结构还是切片来应用完全不同的优化,因此为了衡量性能,您必须查看整体程序及其行为,而不仅仅是一个特定的操作。