Go 如果我知道许多tmp片的最大大小,我应该在创建它们时设置容量吗?
如果我需要在函数中使用tmp片,并且函数将被多次调用,那么它们的最大容量将不会超过10。但它们的长度各不相同。举个例子,也许80%的手机只有1码大小。10%的人穿3号,10%的人穿10号 我可以想到如下示例函数:Go 如果我知道许多tmp片的最大大小,我应该在创建它们时设置容量吗?,go,Go,如果我需要在函数中使用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) { tmp
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)
?还有其他建议吗?我愿意
var tmpSlice []string
这将为您提供一个空字符串片段,您可以根据需要进行追加。
除非切片范围变大,并且您事先知道维度,否则我不会为它预先分配内存如果代码不在堆上分配内存,那么最快的速度将是
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
}
创建在堆栈上分配且不转义的变量(按值传递变量,否则它们将转义)
您可以通过在建筑上添加-gcflags“-m-l”
进行检查
下面的示例显示,如果我们用数组替换slice
,并按值传递它,则会产生无需分配(在堆上)的快速代码
此答案假设
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
overtmpSlice:=make([]string,0,10)
,因为不需要了解10的值从何而来。非常感谢您提供这一技巧。因此,您建议首先将其设置为nil
。好的,干杯^_^这并不能回答问题。非常感谢您的回答。但很抱歉,我不太明白你想表达什么。那么你对我的问题的最后建议是什么?您是否建议使用var tmpSlice[10]字符串
?然后在循环中使用tmpSlice[i]=赋值?最后,当访问它时,再次循环直到最后一个非空字符串?非常感谢。我建议使用切片时不要过早优化。在你发现这个方法非常慢之后,你可以应用我的建议。想象代码的读者看到make([]字符串,0,10)
,为什么是10?为什么不是42?如果没有理由,不要为了避免这种做法而提出更好的问题。数组的问题是很容易编写代码,使它们像切片一样慢。如果它回答了您的问题,请接受答案,这样我就可以用评论中的详细信息更新它。如果searchDb参数没有逃逸,那么编写的函数是最佳选择。该函数将在没有为片分配堆的情况下执行。如果参数真的转义了,那么最佳选择将取决于实际工作负载和运行时在append上分配额外容量的策略。在这种情况下,您需要测量以确定什么是最好的。如果searchDb调用数据库,那么选择之间的性能差异将体现在噪音中。@ThunderCat您好,非常感谢您的回复。很抱歉,我不太明白这里的escape
是什么意思。是的,searchDb将从数据库的名称调用数据库。谢谢
tmpSlice := make([]string, 0, 10)