Java: valore di concorrenza per ConcurrentHashmap
-
13-11-2019 - |
Domanda
Esiste un valore ottimale per il livello di concurrenza oltre il quale le prestazioni di ConcorrentHashmap iniziano a degradare?
Se sì, qual è quel valore e qual è il motivo del degrado delle prestazioni? (Questa domanda si origina nel tentativo di scoprire eventuali limitazioni pratiche che può avere una maestro di concorrente).
Soluzione
Il Javadoc Offre una guida abbastanza dettagliata:
La concorrenza consentita tra le operazioni di aggiornamento è guidata dall'opzione opzionale
concurrencyLevel
Argomento del costruttore (impostazione predefinita 16), che viene utilizzato come suggerimento per il dimensionamento interno.La tabella è partizionata internamente per cercare di consentire il numero indicato di aggiornamenti simultanei senza contesa. Poiché il posizionamento nelle tabelle hash è essenzialmente casuale, la concorrenza effettiva varierà. Idealmente, dovresti scegliere un valore per adattarsi a tutti i thread che mai modificheranno contemporaneamente la tabella. L'uso di un valore significativamente più elevato di quello che serve può sprecare spazio e tempo e un valore significativamente più basso può portare alla contesa del filo. Ma sopravvaluta e sottovaluta all'interno di un ordine di grandezza di solito non hanno un impatto molto evidente. Un valore di uno è appropriato quando è noto che solo un thread si modificherà e tutti gli altri leggono solo.
Riassumere: Il valore ottimale dipende dal numero di aggiornamenti simultanei previsti. Un valore all'interno di un ordine di grandezza dovrebbe funzionare bene. Ci si può aspettare che i valori al di fuori di tale intervallo portino a degrado delle prestazioni.
Altri suggerimenti
Devi farti due domande
- Quanti CPU ho?
- Quale percentuale del tempo sarà a utile Il programma accedi alla stessa mappa?
La prima domanda indica il numero massimo di thread che possono accedere alla mappa contemporaneamente. Puoi avere 10000 thread, ma se hai solo 4 CPU, al massimo 4 funzionano contemporaneamente.
La seconda domanda ti dice che la maggior parte di questi thread accederanno alla mappa e faranno qualcosa di utile. Puoi ottimizzare la mappa per fare qualcosa di inutile (ad es. Micro-Benchmark) ma non c'è punto di messa a punto per questo IMHO. Supponi di avere un programma utile che utilizza molto la mappa. Potrebbe essere spendere il 90% delle volte facendo qualcos'altro, ad esempio, accedendo ad altre mappe, costruendo chiavi o valori, facendo qualcosa con i valori che ottiene dalla mappa.
Supponi di passare il 10% del tempo ad accedere a una mappa su una macchina con 4 CPU. Ciò significa che in media accederai alla mappa in 0,4 thread in media. (O un thread circa il 40% delle volte) In questo caso un livello di concorrenza di 1-4 va bene.
In ogni caso, è probabile che il livello di concorrenza sia superiore al numero di CPU che hai non sia necessario, anche per un micro-Benchmark.
A partire da Java 8, ConcurrentHashMap
parametro costruttore per per concurrencyLevel
è effettivamente inutilizzato, e rimane principalmente per la compatibilità all'indietro. L'implementazione è stata riscritta per utilizzare il primo nodo all'interno di ciascun contenitore hash come blocco per quel contenitore, piuttosto che un numero fisso di segmenti/strisce come nel caso delle versioni precedenti.
In breve, a partire da Java 8, non preoccuparti di impostare il concurrencyLevel
Parametro, purché si imposta un valore positivo (diverso da zero, non negativo), secondo il contratto API.