2017-02-19 8 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です。これはプールマップが有益でないかもしれないと私に思います。ゴランのプーリングマップ

答えて

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) 
}