Эффективные хеш-таблицы на Go
В Go нет недостатка хеш-таблиц. Вы всегда можете использовать встроенную map[Key]Val
, с ошеломительной скоростью обладающую непревзойденным удобством! А изобилие типов Key
, разрешенных к использованию, способно довести до изумления!
Вот только ни указатель, ни слайс не подходят... Невозможно подсунуть свои операции (равенства и хеширования). Но хоть со скоростью все хорошо! (извините, не удержался)
Итого, мне пришлось написать HashMap[K, V any]
, закрывающую проблемы.
------------------8<------------------

В это трудно поверить, но:
Без резервирования памяти (конфигурация
R0
),map[uint64]uint64
работает в1.93
раза медленнееUintMap
! И производит в5.64
раза больше мусора!!А с полным резервированием (
R1
), в1.72
раза медленнее! И аж в16.5
раз больше мусора!!!
Вдумайтесь! На коленке написанная хеш-таблица для целых чисел UintMap
почти в два раза обгоняет ЖУТКО оптимизированную нативную map[uint64]uint64
!! И существенно менее мусорит!!!
Но раз трудно поверить, то давайте проверим:
func MyUintMap() {
const N = umN
//R0| um := lib.NewUintMap(0)
um := lib.NewUintMap(N) //R1|
for i := uint64(0); i < N; i++ {
um.Findsert(i, i+N)
}
lib.Assert(um.Size() == N)
cnt := 0
for i := uint64(0); i < N; i++ {
if *um.Val(um.Find(i)) == i+N {
cnt++
}
if um.Find(i+N) == -1 {
cnt++
}
}
lib.Assert(cnt == N*2)
for i := uint64(0); i < N; i++ {
um.Delete(i)
}
lib.Assert(um.Size() == 0)
}
func GoUintMap() {
const N = umN
//R0| m := make(map[uint64]uint64)
m := make(map[uint64]uint64, N) //R1|
for i := uint64(0); i < N; i++ {
m[i] = i + N
}
lib.Assert(len(m) == N)
cnt := 0
for i := uint64(0); i < N; i++ {
if m[i] == i+N {
cnt++
}
if _, ok := m[i+N]; !ok {
cnt++
}
}
lib.Assert(cnt == N*2)
for i := uint64(0); i < N; i++ {
delete(m, i)
}
lib.Assert(len(m) == 0)
}
Здесь всего-то лишь вставка, два поиска и удаление. Запустите go test -bench=UintMap -benchmem
и увидите сами. Вот только можно ли ругать Google за неэффективный map[uint64]uint64
?
------------------8<------------------
Итоги?
Смело берите
HashMap[K, V any]
для слайсов и указателей!Немного оптимизированная
BytesMap
-- лучший выбор для[]byte
.Интересно оптимизированная
UintMap
-- это выбор для целых чисел. Разберитесь, что там "не так", и используйте за основу.
И как всегда, исходный код, подробности и пару неудачных шуток вы можете найти в моей статье https://ders.by/go/hashmap/hashmap.html