Оптимизация производительности map
Предвыделение памяти
Если размер известен — задай начальную ёмкость через make:
// Без подсказки — многократное перехеширование при росте
m := make(map[string]int)
// С подсказкой — меньше аллокаций
m := make(map[string]int, 10000)
Подсказка не ограничивает размер, только уменьшает количество перехеширований.
Ключи и их стоимость
Стоимость хеширования зависит от типа ключа:
| Тип ключа | Стоимость хеширования |
|---|---|
int | минимальная |
string | O(len) |
struct | O(полей) |
interface | дополнительный boxing |
Для горячих путей используй числовые ключи вместо строковых:
// Медленнее: хеширование строки
cache := map[string]*Result{}
// Быстрее: хеширование числа
type UserID uint64
cache := map[UserID]*Result{}
Альтернативы map для специальных случаев
// Маленькие наборы (n < 10) — линейный поиск по срезу быстрее из-за кэша
type KV struct{ K, V string }
table := []KV{{"a", "1"}, {"b", "2"}}
// Счётчики с ограниченным диапазоном — массив
var freq [256]int
for _, c := range text { freq[c]++ }
// Битовый массив для наличия/отсутствия
var seen [1 << 16]bool
Профилирование
import "runtime"
var before, after runtime.MemStats
runtime.ReadMemStats(&before)
// ... операции с map ...
runtime.ReadMemStats(&after)
fmt.Println("allocs:", after.Mallocs-before.Mallocs)
Для бенчмарков используй testing.B:
func BenchmarkMap(b *testing.B) {
m := make(map[int]int, b.N)
for i := 0; i < b.N; i++ { m[i] = i }
}
Упражнения
| № | Задание | Сложность |
|---|---|---|
| 1 | Упражнение 1 | easy |
| 2 | Упражнение 2 | easy |
| 3 | Упражнение 3 | medium |