Надшвидка хеш-карта C / C ++ (таблиця, словник) [закрито]


84

Мені потрібно зіставити примітивні ключі (int, можливо, довгі) для структурування значень у високопродуктивній структурі даних хеш-карти.

У моїй програмі буде кілька сотень цих карт, і кожна карта, як правило, матиме щонайбільше кілька тисяч записів. Однак карти будуть постійно "освіжати" або "розгортати"; уявіть собі обробку мільйонів addі deleteповідомлень в секунду.

Які бібліотеки на C або C ++ мають структуру даних, яка відповідає цьому випадку використання? Або як би ви порадили побудувати власну? Дякую!


1
Вам потрібно обробити пошук за ключами у ваших даних?
Гійом Лебуржуа

3
чи оновлення або пошук будуть частішими? (додати / видалити або прочитати / оновити, що не змінює клавішу)
фальстро

stackoverflow.com/questions/266206/… . Це, можливо, гарне місце для початку.
DumbCoder

2
@roe:Операції додавання / видалення набагато (у 100 разів) частіше, ніж операції отримання.
Haywood Jablomey,

1
Через чотири з половиною роки було б цікаво дізнатись, що найбільше відповідало вашим потребам. Якщо жодна з поточних відповідей не була задовільною, ви можете написати свою власну та прийняти її.
Вальтер Тросс

Відповіді:


31

Я б рекомендував вам спробувати Google SparseHash (або версію C11 Google SparseHash-c11 ) і перевірити, чи відповідає він вашим потребам. У них є ефективна реалізація пам’яті, а також оптимізована для швидкості. Я давно зробив бенчмарк, це була найкраща реалізація хеш-таблиць з точки зору швидкості (однак з недоліками).


16
Чи можете ви детальніше пояснити, якими були недоліки?
Haywood Jablomey,

IIRC, це була проблема пам'яті, при видаленні елемента елемент був зруйнований, але його пам'ять все ще жива (використовується як кеш, я думаю).
Scharron

4
@Haywood Jablomey: Основним недоліком є ​​те, що він вимагає розділити одне або два (якщо ви коли-небудь стираєте елементи) значення і ніколи не використовувати їх. У деяких випадках це легко зробити, наприклад, негативні інти або подібні речі, але в інших випадках не зовсім так.
дублет

3
Чи підтримали б ви сьогодні цю рекомендацію?
einpoklum

11

Які бібліотеки на C або C ++ мають структуру даних, яка відповідає цьому випадку використання? Або як би ви порадили побудувати власну? Дякую!

Ознайомтеся з масивами Джуді від LGPL'd . Ніколи не використовував себе, але мені рекламували кілька разів.

Ви також можете спробувати порівняти STL-контейнери (std :: hash_map тощо). Залежно від платформи / реалізації та налаштування вихідного коду (попередньо розподілити стільки, скільки ви можете, динамічне управління пам'яттю є дорогим), вони можуть бути достатньо продуктивними.

Крім того, якщо ефективність остаточного рішення перевершує вартість рішення, ви можете спробувати замовити систему з достатньою кількістю оперативної пам'яті, щоб розмістити все в простих масивах. Ефективність доступу за допомогою індексу є неперевершеною.

Операції додавання / видалення набагато (у 100 разів) частіше, ніж операції отримання.

Це натякає на те, що вам спочатку слід сконцентруватися на вдосконаленні алгоритмів. Якщо дані лише записуються, а не читаються, то навіщо їх взагалі писати?


11

Просто використовуйте boost::unordered_map(або tr1тощо) за замовчуванням. Потім сформулюйте свій код і перевірте, чи є цей код вузьким місцем. Тільки тоді я б запропонував точно проаналізувати ваші вимоги, щоб знайти швидший замінник.


15
Це є. VS2013 std::unordered_mapзаймає 90 +% всього мого часу виконання, хоча я використовую карти лише для відносно невеликої частини обробки.
Камерон,

6

Якщо у вас є багатопотокова програма, ви можете знайти кілька корисних хеш-таблиць у бібліотеці будівельних блоків Intel thread . Наприклад, tbb :: concurrent_unordered_map має такий самий api, що і std :: unordered_map, але його основні функції є потокобезпечними.

Також подивіться на бібліотеку глупостей facebook , вона має високопродуктивну одночасну хеш-таблицю та список пропуску .




2

Спочатку перевірте, чи такі рішення, як libmemcache, відповідають вашим потребам.

Якщо ні ...

Карти хеш-карт, здається, є чіткою відповіддю на ваші вимоги. Він забезпечує пошук o (1) на основі клавіш. У наш час більшість бібліотек STL надають певний хеш. Тож використовуйте той, який надає ваша платформа.

Після того, як ця частина буде виконана, вам доведеться протестувати рішення, щоб перевірити, чи є алгоритм хешування за замовчуванням достатньо продуктивним для ваших потреб.

Якщо це не так, вам слід вивчити кілька хороших алгоритмів швидкого хешування, знайдених у мережі

  1. старе добро просте число помножити algo
  2. http://www.azillionmonkeys.com/qed/hash.html
  3. http://burtleburtle.net/bob/
  4. http://code.google.com/p/google-sparsehash/

Якщо це недостатньо добре, ви можете самостійно скотити хеш-модуль, який усуває проблему, яку ви бачили із перевіреними контейнерами STL, та одним із наведених вище алгоритмів хешування. Обов’язково кудись опублікуйте результати.

О, і цікаво, що у вас є кілька карт ... можливо, ви можете спростити, отримавши ключ як 64-бітний номер, використовуючи високі біти, щоб розрізнити, якій карті він належить, і додати всі пари значень ключа до одного гігантського хешу. Я бачив хеші, які мають близько сотні тисяч символів, які чудово працюють на базовому алгоритмі хешування простого числа.

Ви можете перевірити ефективність цього рішення порівняно з сотнями карт .. я думаю, що це може бути краще з точки зору профілювання пам'яті ... будь-ласка, опублікуйте результати десь, якщо вам вдасться виконати цю вправу

Я вважаю, що більше, ніж алгоритм хешування, це може бути постійне додавання / видалення пам'яті (чи можна цього уникнути?) Та профіль використання кешу процесора, який може бути більш важливим для продуктивності вашого додатка

Щасти


2

Спробуйте хеш-таблиці з різних шаблонів контейнерів . Це closed_hash_mapприблизно така ж швидкість, як і швидкість Google dense_hash_map, але простіша у використанні (без обмежень на містяться значення), а також має деякі інші переваги.


2

Я б запропонував uthash . Просто включіть, #include "uthash.h"а потім додайте UT_hash_handleструктуру до і виберіть одне або кілька полів у вашій структурі, щоб виступати в ролі ключа. Слово про продуктивність тут .


1

http://incise.org/hash-table-benchmarks.html gcc має дуже хорошу реалізацію. Однак пам’ятайте, що він повинен поважати дуже погане стандартне рішення:

Якщо відбувається повторне перепрофілювання, усі ітератори втрачають силу, але посилання та вказівники на окремі елементи залишаються дійсними. Якщо фактичного перероблення не відбудеться, змін не буде.

http://www.cplusplus.com/reference/unordered_map/unordered_map/rehash/

Це означає, що в основному стандарт говорить, що реалізація ПОВИННА БУТИ на основі пов'язаних списків. Це запобігає відкритій адресації, яка має кращу продуктивність.

Я думаю, що Google sparse використовує відкриту адресацію, хоча в цих тестах лише щільна версія перевершує конкуренцію. Однак розріджена версія перевершує всю конкуренцію у використанні пам'яті. (також він не має жодного плато, чиста пряма лінія без кількості елементів)


1
Дивіться також це , де обговорюється, як інтерфейс сегмента також вимагає ланцюжка. Суть щодо посилань дуже хороша. Спокусливо посперечатися і сказати, що це корисна гарантія, але в багатьох випадках ми хочемо лише посилань, щоб не шукати елементи знову, і звичайна причина полягає в тому, що пошук занадто повільний ... чого не було б, якби не було повинні зберігати посилання дійсними, а отже, можуть використовувати відкриту адресацію! Отже, це здається трохи куркою та яйцем. Тут наводиться пропозиція 2003 року, в якій явно обговорюється вибір.
underscore_d
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.