3 回答
TA贡献1859条经验 获得超6个赞
最快的是代码不在堆上分配。
创建在堆栈上分配且不转义的变量(按值传递变量,否则它们将转义)。
-gcflags "-m -l"逃避你可以通过添加建筑物来检查。
这是一个示例,显示如果我们slice用数组替换并按值传递它,它会产生快速代码而无需分配(在堆上)。
package main
import "testing"
func BenchmarkAllocation(b *testing.B) {
b.Run("Slice", func(b2 *testing.B) {
for i := 0; i < b2.N; i++ {
_ = getDataFromDbSlice([]string{"one", "two"})
}
})
b.Run("Array", func(b2 *testing.B) {
for i := 0; i < b2.N; i++ {
_ = getDataFromDbArray([]string{"one", "two"})
}
})
}
type DbQuery [10]string
type DbQueryResult [10]string
func getDataFromDbArray(s []string) DbQueryResult {
q := DbQuery{}
return processQueryArray(q)
}
func processQueryArray(q DbQuery) DbQueryResult {
return (DbQueryResult)(q)
}
func getDataFromDbSlice(s []string) []string {
tmpArray := make([]string, 0, 10)
return processQuerySlice(tmpArray)
}
func processQuerySlice(q []string) []string {
return q
}
运行基准测试benchmem给出了以下结果:
BenchmarkAllocation/Slice-6 30000000 51.8 ns/op 160 B/op 1 allocs/op
BenchmarkAllocation/Array-6 100000000 15.7 ns/op 0 B/op 0 allocs/op
TA贡献1821条经验 获得超4个赞
该答案假定searchDB不保留对传递给它的切片的引用。给定变量和函数名称,函数似乎不太可能保留引用。
这些选项具有相同的内存和性能特征:
var tmpSlice []string
tmpSlice := []string{}
tmpSlice := make([]string, 0)
tmpSlice := make([]string, 0, 0)
在第一个追加操作之前,它们都不会分配内存。如果这些是您唯一的选择,那么请选择前两个中的一个,因为它们更容易阅读。
此选项将具有最佳性能:
tmpSlice := make([]string, 0, 10)
这确保了切片的后备数组被分配一次。附加值时不会重新分配支持数组。
如果searchDB的参数没有逃逸,那么将在堆栈上为后备数组分配一次。这是最好的表现。您可以通过使用选项构建来确定参数是否逃逸-gcflags "-m -l"。
鉴于getDataFromDb调用数据库操作,选项之间的任何性能差异都将被忽略。编写清晰简单的代码比优化它更重要。
我可能会选择var tmpSlice []stringover tmpSlice := make([]string, 0, 10),因为没有必要了解前者的值 10 从何而来。
TA贡献1886条经验 获得超2个赞
我会做
var tmpSlice []string
这会给你一个空字符串切片,你可以根据需要追加。除非切片范围变大并且您事先知道维度,否则我不会为它预分配内存
- 3 回答
- 0 关注
- 137 浏览
添加回答
举报