2017-02-19 79 views
1

我很好奇,如果有人曾嘗試在Go中使用pool地圖嗎?我之前已經閱讀過關於pooling buffers的信息,並且我想知道如果通過類似的推理,如果必須頻繁地創建和銷燬地圖,或者有任何原因,先驗地可能效率不高,則可以合併地圖。當地圖返回到游泳池時,必須遍歷它並刪除所有元素,但它似乎是一個受歡迎的推薦是create a new map instead of deleting the entries in a map which has already been allocated and reusing it,這使我認爲彙集地圖可能沒有那麼有益。在Golang中彙集地圖

回答

1

如果你的地圖通過刪除或添加條目來改變(很多)的大小,這將導致新的分配,並且沒有將它們合併的好處。

如果你的地圖大小不會改變,但只有密鑰的值會改變,那麼合併將是一個成功的優化。

當您讀取類似於表格的結構時,例如CSV文件或數據庫表格,這可以很好地工作。每行將包含完全相同的列,所以您不需要清除任何條目。

下面的基準測試顯示,當與go test -benchmem -bench .運行

package mappool 

import "testing" 

const SIZE = 1000000 

func BenchmarkMap(b *testing.B) { 
    m := make(map[int]int) 

    for i := 0; i < SIZE; i++ { 
     m[i] = i 
    } 

    b.ResetTimer() 

    for i := 0; i < b.N; i++ { 
     for i := 0; i < SIZE; i++ { 
      m[i] = m[i] + 1 
     } 
    } 
} 
1

像@Grzegorz祖爾說,如果你的地圖大小不發生很大的變化,然後集中是有幫助的任何分配。爲了測試這一點,我做了一個基準,在彙集勝出。我的機器上輸出是:

Pool time: 115.977µs 
No-pool time: 160.828µs 

基準代碼:

package main 

import (
    "fmt" 
    "math/rand" 
    "time" 
) 

const BenchIters = 1000 

func main() { 
    pool := map[int]int{} 
    poolTime := benchmark(func() { 
     useMapForSomething(pool) 

     // Return to pool by clearing the map. 
     for key := range pool { 
      delete(pool, key) 
     } 
    }) 

    nopoolTime := benchmark(func() { 
     useMapForSomething(map[int]int{}) 
    }) 

    fmt.Println("Pool time:", poolTime) 
    fmt.Println("No-pool time:", nopoolTime) 
} 

func useMapForSomething(m map[int]int) { 
    for i := 0; i < 1000; i++ { 
     m[rand.Intn(300)] += 5 
    } 
} 

// benchmark measures how long f takes, on average. 
func benchmark(f func()) time.Duration { 
    start := time.Now().UnixNano() 
    for i := 0; i < BenchIters; i++ { 
     f() 
    } 
    return time.Nanosecond * time.Duration((time.Now().UnixNano()-start)/BenchIters) 
}