Mappa hash C / C ++ ad altissime prestazioni (tabella, dizionario) [chiuso]


86

Ho bisogno di mappare le chiavi primitive (int, forse long) ai valori della struttura in una struttura dati della mappa hash ad alte prestazioni.

Il mio programma avrà alcune centinaia di queste mappe e ogni mappa avrà generalmente al massimo alcune migliaia di voci. Tuttavia, le mappe saranno costantemente "aggiornate" o "agitate"; immagina di elaborare milioni di adde deletemessaggi al secondo.

Quali librerie in C o C ++ hanno una struttura dati che si adatta a questo caso d'uso? Oppure, come consiglieresti di costruirne uno tuo? Grazie!


1
Hai bisogno di elaborare la ricerca per chiavi nei tuoi dati?
Guillaume Lebourgeois

3
gli aggiornamenti o i recuperi saranno più frequenti? (aggiungi / cancella, o leggi / aggiorna che non cambia la chiave)
falstro

stackoverflow.com/questions/266206/… . Questo forse è un buon punto di partenza.
DumbCoder

2
@roe:Le operazioni di aggiunta / eliminazione sono molto (100 volte) più frequenti dell'operazione get.
Haywood Jablomey

1
Dopo quattro anni e mezzo sarebbe interessante sapere cosa si adatta meglio alle tue esigenze. Se nessuna delle risposte attuali è soddisfacente, puoi scrivere la tua e accettarla.
Walter Tross

Risposte:


31

Ti consiglierei di provare Google SparseHash (o la versione C11 di Google SparseHash-c11 ) e vedere se si adatta alle tue esigenze. Hanno un'implementazione efficiente in termini di memoria e ottimizzata per la velocità. Ho fatto un benchmark molto tempo fa, era la migliore implementazione di hashtable disponibile in termini di velocità (ma con degli svantaggi).


16
Puoi approfondire quali erano gli svantaggi?
Haywood Jablomey

IIRC, era un problema di memoria, quando si rimuoveva un elemento, l'elemento è stato distrutto ma la sua memoria era ancora viva (usata come cache immagino).
Scharron

4
@ Haywood Jablomey: Lo svantaggio principale è che richiede di dividere uno o due (se mai cancelli elementi) valori e non usarli mai. In alcuni casi questo è facile da fare, ad esempio int negativi o simili, ma in altri casi non proprio così.
doublep

3
Oggi manterresti questa raccomandazione?
einpoklum

11

Quali librerie in C o C ++ hanno una struttura dati che si adatta a questo caso d'uso? Oppure, come consiglieresti di costruirne uno tuo? Grazie!

Controlla gli array Judy LGPL . Non mi sono mai usato, ma mi è stato pubblicizzato in poche occasioni.

Puoi anche provare a confrontare i contenitori STL (std :: hash_map, ecc.). A seconda della piattaforma / implementazione e dell'ottimizzazione del codice sorgente (preallocare il più possibile la gestione dinamica della memoria è costosa) potrebbero essere sufficientemente performanti.

Inoltre, se le prestazioni della soluzione finale superano il costo della soluzione, puoi provare a ordinare il sistema con RAM sufficiente per mettere tutto in array semplici. Le prestazioni di accesso per indice sono imbattibili.

Le operazioni di aggiunta / eliminazione sono molto (100 volte) più frequenti dell'operazione get.

Ciò suggerisce che potresti voler concentrarti prima sul miglioramento degli algoritmi. Se i dati vengono solo scritti, non letti, perché scriverli?


11

Basta usare boost::unordered_map(o tr1ecc.) Per impostazione predefinita. Quindi profilare il codice e vedere se quel codice è il collo di bottiglia. Solo allora ti suggerirei di analizzare con precisione le tue esigenze per trovare un sostituto più veloce.


15
È. VS2013 std::unordered_mapsta impiegando il 90% del mio intero tempo di esecuzione, anche se utilizzo le mappe solo per una parte relativamente piccola dell'elaborazione.
Cameron




2

Prima controlla se le soluzioni esistenti come libmemcache soddisfano le tue esigenze.

Altrimenti ...

Le mappe hash sembrano essere la risposta definitiva alle tue esigenze. Fornisce o (1) ricerca in base alle chiavi. La maggior parte delle librerie STL fornisce una sorta di hash in questi giorni. Quindi usa quello fornito dalla tua piattaforma.

Una volta completata quella parte, devi testare la soluzione per vedere se l'algoritmo di hashing predefinito è abbastanza buono in termini di prestazioni per le tue esigenze.

Se non lo è, dovresti esplorare alcuni buoni algoritmi di hashing veloce trovati in rete

  1. buon vecchio numero primo moltiplicare algo
  2. http://www.azillionmonkeys.com/qed/hash.html
  3. http://burtleburtle.net/bob/
  4. http://code.google.com/p/google-sparsehash/

Se questo non è abbastanza buono, potresti lanciare un modulo di hashing da solo, che risolve il problema che hai visto con i contenitori STL che hai testato e uno degli algoritmi di hashing sopra. Assicurati di pubblicare i risultati da qualche parte.

Oh, ed è interessante che tu abbia più mappe ... forse puoi semplificare avendo la tua chiave come un num a 64 bit con i bit alti usati per distinguere a quale mappa appartiene e aggiungere tutte le coppie di valori chiave a un hash gigante. Ho visto hash che hanno circa centomila simboli funzionare perfettamente bene sull'algoritmo di hashing dei numeri primi di base.

Puoi controllare come si comporta quella soluzione rispetto a centinaia di mappe .. penso che potrebbe essere migliore dal punto di vista della profilazione della memoria ... per favore pubblica i risultati da qualche parte se riesci a fare questo esercizio

Credo che più dell'algoritmo di hashing potrebbe essere l'aggiunta / eliminazione costante della memoria (può essere evitata?) E il profilo di utilizzo della cache della CPU che potrebbe essere più cruciale per le prestazioni della tua applicazione

in bocca al lupo


2

Prova le tabelle hash da vari modelli di contenitori . La sua closed_hash_mapè circa la stessa velocità di Google dense_hash_map, ma è più facile da usare (nessuna restrizione sui valori contenuti) e ha alcuni altri vantaggi pure.


2

Suggerirei uthash . Basta includere #include "uthash.h"quindi aggiungere un UT_hash_handlealla struttura e scegliere uno o più campi nella struttura che fungano da chiave. Una parola sulle prestazioni qui .


1

http://incise.org/hash-table-benchmarks.html gcc ha un'implementazione molto buona. Tuttavia, tieni presente che deve rispettare una decisione standard pessima:

Se si verifica un rehash, tutti gli iteratori vengono invalidati, ma i riferimenti e i puntatori ai singoli elementi rimangono validi. Se non avviene alcun rehash effettivo, nessuna modifica.

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

Ciò significa che fondamentalmente lo standard dice che l'implementazione DEVE ESSERE basata su elenchi concatenati. Impedisce l'indirizzamento aperto che ha prestazioni migliori.

Penso che google sparse stia usando l'indirizzamento aperto, anche se in questi benchmark solo la versione densa supera la concorrenza. Tuttavia, la versione sparsa supera tutta la concorrenza nell'utilizzo della memoria. (inoltre non ha alcun plateau, pura linea retta rispetto al numero di elementi)


1
Vedi anche questo , che discute come anche l'interfaccia del bucket richiede il concatenamento. Il punto sui riferimenti è molto buono. Si è tentati di discutere e dire che è una garanzia utile, ma in molti casi vogliamo solo riferimenti per evitare di cercare di nuovo gli elementi, e la solita ragione è perché la ricerca è troppo lenta ... cosa che non sarebbe se non fosse devono mantenere i riferimenti validi e quindi potrebbe utilizzare l'indirizzamento aperto! Quindi sembra un po 'gallina e uovo. Si cita la proposta del 2003, discutendo esplicitamente la scelta.
underscore_d
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.