根据下面所示的 Go 基准(通过运行
go test -v -bench=. -benchmem
),将一个字节数组附加到数组中,每次操作需要 1 个分配。
Benchmark_AddOneByteArray-4 1986709 581.2 ns/op 1792 B/op 1 allocs/op
但是,附加 2 字节数组每次操作需要 101 次分配,与附加 32 字节数组(101 次分配)相同
Benchmark_AddTwoByteArray
Benchmark_AddTwoByteArray-4 529726 2235 ns/op 1992 B/op 101 allocs/op
Benchmark_AddThirtyTwoByteArray
Benchmark_AddThirtyTwoByteArray-4 282092 4431 ns/op 4992 B/op 101 allocs/op
为什么附加一字节数组每个操作仅花费 1 次分配,而测试的所有其他大小的每个操作花费 101 次分配?
func addOneByteArray(n int) []any {
my_array := make([]any, n)
for i := 0; i < n; i++ {
my_array[i] = [1]byte{}
}
return my_array
}
func addTwoByteArray(n int) []any {
my_array := make([]any, n)
for i := 0; i < n; i++ {
my_array[i] = [2]byte{}
}
return my_array
}
func addThirtyTwoByteArray(n int) []any {
my_array := make([]any, n)
for i := 0; i < n; i++ {
my_array[i] = [32]byte{}
}
return my_array
}
var N = 100
func Benchmark_AddOneByteArray(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = addOneByteArray(N)
}
}
func Benchmark_AddTwoByteArray(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = addTwoByteArray(N)
}
}
func Benchmark_AddThirtyTwoByteArray(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = addThirtyTwoByteArray(N)
}
}
当值可以适合界面表示时,这是对界面的优化。
通常,一个接口被表示为一个带有两个指针的数据块;一个是指向接口元数据的指针,另一个是指向其值的指针。但是,当该值不大于指针时,会进行优化以使该值适合接口块本身。
感谢@rocka2q提供线索。
请注意,这是 golang 运行时代码中的优化,而不是编译器中的优化,因此更改编译器优化选项不会产生影响。