如果我知道许多 tmp 切片的最大大小,我应该在创建它们时设置容量吗?

如果我需要在一个函数中使用 tmp 切片,并且该函数会被多次调用,它们的最大容量不会超过 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)?或任何其他建议?


摇曳的蔷薇
浏览 138回答 3
3回答

慕丝7291255

最快的是代码不在堆上分配。创建在堆栈上分配且不转义的变量(按值传递变量,否则它们将转义)。-gcflags "-m -l"逃避你可以通过添加建筑物来检查。这是一个示例,显示如果我们slice用数组替换并按值传递它,它会产生快速代码而无需分配(在堆上)。package mainimport "testing"func BenchmarkAllocation(b *testing.B) {&nbsp; &nbsp; b.Run("Slice", func(b2 *testing.B) {&nbsp; &nbsp; &nbsp; &nbsp; for i := 0; i < b2.N; i++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _ = getDataFromDbSlice([]string{"one", "two"})&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; })&nbsp; &nbsp; b.Run("Array", func(b2 *testing.B) {&nbsp; &nbsp; &nbsp; &nbsp; for i := 0; i < b2.N; i++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _ = getDataFromDbArray([]string{"one", "two"})&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; })}type DbQuery [10]stringtype DbQueryResult [10]stringfunc getDataFromDbArray(s []string) DbQueryResult {&nbsp; &nbsp; q := DbQuery{}&nbsp; &nbsp; return processQueryArray(q)}func processQueryArray(q DbQuery) DbQueryResult {&nbsp; &nbsp; return (DbQueryResult)(q)}func getDataFromDbSlice(s []string) []string {&nbsp; &nbsp; tmpArray := make([]string, 0, 10)&nbsp; &nbsp; return processQuerySlice(tmpArray)}func processQuerySlice(q []string) []string {&nbsp; &nbsp; return q}运行基准测试benchmem给出了以下结果:BenchmarkAllocation/Slice-6&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;30000000&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 51.8 ns/op&nbsp; &nbsp; &nbsp; &nbsp;160 B/op&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1 allocs/opBenchmarkAllocation/Array-6&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;100000000&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;15.7 ns/op&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0 B/op&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0 allocs/op

收到一只叮咚

&nbsp; &nbsp; 该答案假定searchDB不保留对传递给它的切片的引用。给定变量和函数名称,函数似乎不太可能保留引用。这些选项具有相同的内存和性能特征:&nbsp;var tmpSlice []string&nbsp;tmpSlice := []string{}&nbsp;tmpSlice := make([]string, 0)&nbsp;tmpSlice := make([]string, 0, 0)在第一个追加操作之前,它们都不会分配内存。如果这些是您唯一的选择,那么请选择前两个中的一个,因为它们更容易阅读。此选项将具有最佳性能:tmpSlice := make([]string, 0, 10)这确保了切片的后备数组被分配一次。附加值时不会重新分配支持数组。如果searchDB的参数没有逃逸,那么将在堆栈上为后备数组分配一次。这是最好的表现。您可以通过使用选项构建来确定参数是否逃逸-gcflags "-m -l"。鉴于getDataFromDb调用数据库操作,选项之间的任何性能差异都将被忽略。编写清晰简单的代码比优化它更重要。我可能会选择var tmpSlice []stringover tmpSlice := make([]string, 0, 10),因为没有必要了解前者的值 10 从何而来。

MM们

我会做var&nbsp;tmpSlice&nbsp;[]string这会给你一个空字符串切片,你可以根据需要追加。除非切片范围变大并且您事先知道维度,否则我不会为它预分配内存
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go