這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
在開發過程中,我們總是在設計不同的資料結構和不同的演算法對資料進行組織和存取,有些場合我們可以用寫入程式碼或者代碼產生器來產生一組函數按條件返回資料,另外一些場合我們可以把資料存放區在slice當中,需要尋找時就遍曆尋找,又或者有的場合我們可以用map儲存資料,用key來索引資料。這幾種資料存取方式在不同資料量的情況下,效能消耗是怎麼樣的呢?下面做個對比實驗。
我們知道go的map資料量不管大小都能保證固定的讀取時間,而slice和寫入程式碼肯定無法應對大資料量,所以這裡不做大資料量的實驗,只做小資料量的實驗。
實驗代碼(github):
package labs06import "testing"type BigStruct struct { C01 int C02 int C03 int C04 int C05 int C06 int C07 int C08 int C09 int C10 int C11 int C12 int C13 int C14 int C15 int C16 int C17 int C18 int C19 int C20 int C21 int C22 int C23 int C24 int C25 int C26 int C27 int C28 int C29 int C30 int}func Loop1(a []BigStruct) int { for i := 0; i < len(a); i++ { if a[i].C30 == 3 { return i } } return -1}func Loop2(a []BigStruct) int { for i := len(a) - 1; i >= 0; i-- { if a[i].C30 == 1 { return i } } return -1}func Loop3(a map[int]BigStruct) int { return a[2].C30}func Loop4(a []*BigStruct) int { for i, x := range a { if x.C30 == 3 { return i } } return -1}func Loop5(a []BigStruct) int { switch { case a[0].C01 == 3: return 0 case a[1].C01 == 3: return 1 case a[2].C01 == 3: return 2 } return -1}func Benchmark_Loop1(b *testing.B) { var a = make([]BigStruct, 3) a[0].C30 = 1 a[1].C30 = 2 a[2].C30 = 3 for i := 0; i < b.N; i++ { Loop1(a) }}func Benchmark_Loop2(b *testing.B) { var a = make([]BigStruct, 3) a[0].C30 = 1 a[1].C30 = 2 a[2].C30 = 3 for i := 0; i < b.N; i++ { Loop2(a) }}func Benchmark_Loop3(b *testing.B) { var a = make(map[int]BigStruct, 3) a[0] = BigStruct{C30: 1} a[1] = BigStruct{C30: 2} a[2] = BigStruct{C30: 3} for i := 0; i < b.N; i++ { Loop3(a) }}func Benchmark_Loop4(b *testing.B) { var a = make([]*BigStruct, 3) a[0] = &BigStruct{C30: 1} a[1] = &BigStruct{C30: 2} a[2] = &BigStruct{C30: 3} for i := 0; i < b.N; i++ { Loop4(a) }}func Benchmark_Loop5(b *testing.B) { var a = make([]BigStruct, 3) a[0].C30 = 1 a[1].C30 = 2 a[2].C30 = 3 for i := 0; i < b.N; i++ { Loop5(a) }}
實驗結果:
dada-imac:labs dada$ go test -test.bench="." labs06testing: warning: no tests to runPASSBenchmark_Loop1 500000000 5.73 ns/opBenchmark_Loop2 500000000 5.72 ns/opBenchmark_Loop3 50000000 68.0 ns/opBenchmark_Loop4 500000000 4.92 ns/opBenchmark_Loop5 500000000 4.40 ns/opok labs06 15.970s
結論:寫入程式碼 < 指標slice的range迴圈 < for迴圈,但是量級是一樣的,看情況用。但是map差了一個量級,小資料量盡量少用。