代码的顺序和性能

huangapple go评论77阅读模式
英文:

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)

}

为什么性能取决于我先写入什么?我先写入的那个似乎更慢。为什么会这样?

英文:

I wanted to find which is faster: struct vs array. So I wrote a GO code in which I write 4 int values (1,2,3 and 4) to the members of a structure and then to an array of length 4. I tried to find the time it takes to write.

Case1: First, I write values to a structure and then to an array. Here I found array to be faster than structure.

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)

}

Case2: Second, I write values to an array and then a structure. Here I found structure to be faster than array.

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)

}

Why the performance depends on to what I write first? The one that I write to first appears to be slower. Why is it so?

答案1

得分: 13

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

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

在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倍。如果重新排序基准函数,你将得到类似(非常接近)的结果。

英文:

Running any code for the first time may have some (significant) overhead, e.g. related code may be loaded, many things may be deferred until they are needed (e.g. internal buffers). Running the same thing again may take significantly less time, the difference may even be several orders of magnitude.

Whenever you want to measure execution times, you should run it many times, measure the execution time of the multiple runs, and calculate average time. It's also a good idea to exclude the first (some) runs from the calculation for the above mentioned reasons.

In Go, best and easiest is to use test files and benchmark functions. Read the package doc of testing for more details and examples.

Your case can be benchmarked like this:

package main

import &quot;testing&quot;

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

func BenchmarkSlice(b *testing.B) {
	a := make([]int, 4)
	for i := 0; i &lt; 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 &lt; b.N; i++ {
		a.a = 1
		a.b = 2
		a.c = 3
		a.d = 4
	}
}

Save it to a file like something_test.go, run it with go test -bench .. Output:

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

You can see that using a struct is roughly 4 times faster. You will get similar (very close) results if you reorder the benchmark functions.

答案2

得分: 1

另一个答案解释了时间差异,让我们来看看结构体和切片。

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

英文:

The other answer explained the timing difference, let's get into struct vs. slice.

If the compiler can figure out at compile time that the slice is big enough, accessing the elements of the slice and a struct will generate identical code. Of course, in reality, often the compiler won't know how big the slice is and completely different optimizations will be applied depending on if you're working with a struct or a slice, so for measuring performance you have to look at a whole program and its behavior, not just one particular operation.

huangapple
  • 本文由 发表于 2017年1月12日 16:44:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/41608578.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定