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條經驗 獲得超5個贊
該答案假定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 關注
- 184 瀏覽
添加回答
舉報