2017-02-19 4 views
1

Мне было любопытно, если кто-то попытался pool карты в Go before? Я уже читал о 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 

Benchmark код:

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) 
} 
Смежные вопросы