如果我需要在一个函数中使用tmp slice,并且该函数将被调用多次,它们的最大容量将不会超过10。但是它们的长度是变化的。举例来说,也许其中80%的尺寸为1。10%的尺寸为3,而10%的尺寸为10。
我可以想到一个示例函数,如下所示:
func getDataFromDb(s []string) []string {
tmpSlice := make([]string, 0, 10)
for _, v := range s {
if check(v) {
tmpSlice = append(tmpSlice, v)
}
}
......
return searchDb(tmpSlice)
}
所以我应该做var tmpSlice []string
,tmpSlice := make([]string, 0, 0)
,tmpSlice := make([]string, 0, 5)
或tmpSlice := make([]string, 0, 10)
吗?或其他建议?
答案 0 :(得分:3)
最快的情况是代码没有在堆上分配。
创建在堆栈上分配且不进行转义的变量(按值传递变量,否则它们将转义)。
通过在建筑物上添加-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
答案 1 :(得分:1)
此答案假定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 []string
而不是tmpSlice := make([]string, 0, 10)
,因为不需要了解值10来自何处。
答案 2 :(得分:0)
我会
var tmpSlice []string
这将为您提供一个空字符串切片,您可以根据需要追加。 除非切片范围变大并且您事先知道尺寸,否则我不会为此预先分配内存