posts - 504, comments - 1656, trackbacks - 139

Performance di Hashtable, Collection e Dictionary

Che le performance di Hashtable/Dictionary sulla ricerca di item sia superiore è cosa stranota e messa in grande evidenza su MSDN.

Spesso però sui newsgroup leggo di persone che non usano il contenitore giusto e quindi ho deciso di mettere giù qualche numero per le operazioni più frequenti: Add e Contains. La prova è molto spartana ed è giusto per vedere l'ordine di grandezza.

Hashset<> è una nuova classe del Framework 3.5 studiata per Linq e mediamente più veloce del Dictionary.

In tutto questo la Hashtable è comunque vincente e il perché è semplice: Hashtable è thread-safe per multiple-reader e un writer. In applicazioni multithreading più di una volta l'ho usata per questo motivo e consente di evitare totalmente una montagna di lock. Se esiste la possibilità di avere più di un writer, è sufficiente mettere i lock solo sulle operazioni di scrittura e questo semplifica drasticamente il codice.

List<> è comunque una scelta valida per l'uso più tipico delle collection, l'accesso indicizzato. Non è quindi per nulla bocciata.

Una delle prossime modifiche alla mia RafCollection sarà proprio quella di costruire gli indici con dei Dictionary da usarsi con la AddIndex/RemoveIndex di IBindingList.

1 Milione di Add:

Collection_Perf_Add

1 Milione di Add + 1 Milione di Contains su un elemento non in lista

Collection_Perf_Add_Contains

Le Contains su List<T> sono così lente che ho dovuto interrompere l'elaborazione dopo diverse decine di minuti.

Adesso pensiamo di aggiungere al nostro business layer una Hashtable o Dictionary condiviso tra tutti gli utenti che mantenga in memoria gli indici dei dati delle tabelle più critiche sul DB. Voi mi direte che sto duplicando il lavoro che fa già egregiamente il DB (ed è vero), ma io rispondo che in certi casi può alleggerire molto significativamente il carico, permettendo forte scalabilità. Se teniamo conto che la Hashtable può essere presente su tutti gli application server mentre di DB ce n'è uno solo ...

Print | posted on giovedì 20 dicembre 2007 10.58 |

Feedback

Gravatar

# re: Performance di Hashtable, Collection e Dictionary

Interessante come sempre, il tuo post mi cade a fagiolo. Prossimamente farai modifiche alla RafCollection per integrare il supporto a Linq ????
http://www.codeplex.com/RafCollection/Thread/View.aspx?ThreadId=19102
Ciao
Stefano
20/12/2007 12.04 | Stefano Paparesta
Gravatar

# re: Performance di Hashtable, Collection e Dictionary

Si, è una delle cose che ho in mente.
Sto valutando la possibilità di creare un Linq provider ma il lavoro è tanto e lungo.
La vera sfida con Linq diventa l'implementazione efficiente della ricerca, altrimenti se mi limito a scorrere le liste con IEnumerable le performance se ne vanno.
20/12/2007 12.28 | Raffaele Rialdi
Gravatar

# re: Performance di Hashtable, Collection e Dictionary

Attendo fiducioso !
20/12/2007 14.33 | Stefano Paparesta
Gravatar

# re: Performance di Hashtable, Collection e Dictionary

Non capisco perché hai fatto un test su Add e poi su Add + Contains. E' chiaro che container di tipo Hash hanno costi maggiori sull'Add e minori sulla ricerca. Ma a questo punto non aveva più senso fare un test solo su N Contains e paragonare qual'è il più efficiente tra Dictionary /HashTable e List? Così come hai fatto tu mi devo calcolare il Delta a memoria...

Forse mi sfugge qualche cosa?

Ok per il discorso del Thread Safe e sul fatto di utilizzare una struttura dati di questo tipo piuttosto che il DB. Mi stupisce che ci sia gente che è ancora convinta che il DB sia comunque più efficiente di una struttura Hash in memoria.

Purtroppo c'è troppa gente DB driven e poco CS driven :-D

Comunque complimenti come sempre per i tuoi post.

Ciao
21/12/2007 10.34 | Roberto Scaccia
Gravatar

# re: Performance di Hashtable, Collection e Dictionary

Ho scritto che era una misurazione molto spartana. Mi interessa vedere solo l'ordine di grandezza, altrimenti devi poi vedere il codice IL effettivamente prodotto e farlo girare su un PC totalmente scarico di servizi e applicazioni per poter eseguire un test che possa essere chiamato accurato.

Sui DB conduco lotte continue. Io riconosco gli enormi pregi dell'engine dei DB, ma ci sono persone si ostinano a usarli come se fossimo ancora negli anni settanta.
Grazie e ciao!
21/12/2007 13.24 | Raffaele Rialdi
Gravatar

# re: Performance di Hashtable, Collection e Dictionary

Scusa Raffale, ma se ho capito bene i numeri che mostri nelle tue prove sono il tempo complessivo impiegato per fare un milione di Add, nel caso del primo test, e di un milione di Add + un milione di Contains nel secondo. Dal tuo benchmark posso dedurre soltanto che la Add della Hashtable è molto meno performante delle altre.

Anche facendo la sottrazione tra i tempi dei due test, come scrive Roberto, ottengo che la Contains della Hashtable, per una ricerca di un elemento inesistente, e' comunque più lenta di quella del Dictionary.

Insomma, non capisco proprio in che modo questo benchmark, per quanto qualitativo, dimostrerebbe le migliori performace della Hashtable. Se l'obiettivo non era dimostrare questo, allora non ho capito il tuo post. :-D

Cosa mi sfugge?
23/12/2007 16.22 | Sergio
Gravatar

# re: Performance di Hashtable, Collection e Dictionary

Ciao Sergio, il vantaggio dell'hashtable è quello di essere thread-safe! Essere thread safe ha un costo non indifferente e qui lo si vede chiaramente. Ma se hai bisogno della thread-safety hashtable è impagabile perché è safe per multiple reader e un writer, cosa estremamente comoda.
Se invece la thread safety non ti interessa, allora Hashset e Dictionary sono più performanti.
La list come sempre è scarsissima di performance nelle Contains.
Ognuna di quelle classi ha il suo uso ottimale, lo scopo del post è quello di accendere dubbi affinché ognuno ragioni sulla scelta più opportuna a seconda delle proprie necessità.
23/12/2007 22.12 | Raffaele Rialdi
Gravatar

# re: Performance di Hashtable, Collection e Dictionary

E ci sei riuscito! Hai acceso dei giusti dubbi e delle riflessioni che sono sempre più rare.

Come sempre, un grazie.

Roberto
24/12/2007 12.02 | Roberto Scaccia
Gravatar

# re: Performance di Hashtable, Collection e Dictionary

Prego! :)
24/12/2007 13.43 | Raffaele Rialdi
Gravatar

# re: Performance di Hashtable, Collection e Dictionary

Mi sento di dissentire un pochetto dal post :-) Concordo con l'affermazione "Spesso però sui newsgroup leggo di persone che non usano il contenitore giusto e quindi ho deciso di mettere giù qualche numero per le operazioni più frequenti".

Dal mio punto di vista la collezione "ottimale" deve tenere in considerazione vari aspetti:

1. usage pattern: si fanno più inserimenti oppure letture? Un inserimento one shot e poi solo letture (es catalogo in cache)? Come leggo i dati (per chiave, per indice, enumerazione, ...)?

2. threading: è legato al punto 1. Potrei usare la collezione in multi-threading ed avere l'inizializzazione in single thread.

3. content distribution: come sono distribuiti i miei dati? Ordinati, non ordinati?

4. memory pressure: ho problemi di memoria? Mi serve una struttura dati molto snella?

A volte la risposta non sta nella BCL e bisogna implementarsi la collezione che soddisfi tutti i requisiti. Ad esempio recentemente ho dovuto implementare una red-black list la quale risultava ben più performante di tutte le altre proposte.

Saluti :-)
31/12/2007 6.59 | Pierre
Gravatar

# re: Performance di Hashtable, Collection e Dictionary

Ciao Pierre,
non capisco in cosa dissenti :)
Che il problema sia più vasto concordo, infatti la mia RafCollection su Codeplex affronta tutta un'altra serie di problematiche relative alle collection evolute.
Questo post serviva solo ad evidenziare le differenze più macroscopiche (l'ordine di grandezza dal punto di vista delle performance) su queste classi che sono tipicamente le più usate.
L'enumerazione piatta (IEnumerable) è la meno significativa e non l'ho presa in considerazione in quanto scorrere gli elementi è performante sia sulle liked list che sulle collection basate su array come List<T>.
L'ordinamento credo che faccia parte di quelle feature avanzate che questo post non indirizza (e che ho indirizzato invece in RafCollection perché solleva una serie di problematiche a catena come l'uso di IComparer oppure Reflection).
Ciao!
31/12/2007 16.09 | Raffaele Rialdi
Gravatar

# re: Performance di Hashtable, Collection e Dictionary

Post come sempre molto interessante, avrebbe senso allora confrontare il tutto anche con le powercollection (http://www.wintellect.com/PowerCollections.aspx) di Richter.
Cmq è vero che molto spesso le persone non si pongono il problema di quale struttura dati utilizzare e va a finire che si utilizza sempre la stessa. Sebbene l'ottimizzazione sia una cosa da fare solo dopo appositi test, conoscere pregi/difetti delle principali strutture dati è indubbiamente necessario per fare fin dall'inizio le scelte più intelligenti.

Alk.
02/01/2008 9.20 | Gian Maria
Gravatar

# re: Performance di Hashtable, Collection e Dictionary

Ciao Raf.
Ma sai come List<T> implementa il Contains internamente? Itera su tutti gli oggetti? E' per questo che è così lento nella ricerca? Inoltre, se non ho capito male, senza le Hashtable dovremmo implementarci a manina il controllo del Lock, in caso di multithreading?
21/01/2008 8.43 | Antonio
Gravatar

# re: Performance di Hashtable, Collection e Dictionary

@Antonio. Si, certo itera tutti gli elementi e non potrebbe fare diversamente. Le hashtable si basano sull'intero generato dalla procedura di hash e quindi la loro comparazione durante l'iterazione è decisamente più performante.
Vera anche la seconda. Fai sempre riferimento a msdn per sapere cos'è e cosa non è thread-safe. In ogni classe è ben specificato se è thread-safe.
Ciao
22/01/2008 14.57 | Raffaele Rialdi

Post Comment

Title  
Name  
Email
Url
Comment   
Please add 3 and 3 and type the answer here:

Powered by: