ReaderWriterLockSlim vs. Monitor
-
03-07-2019 - |
Domanda
Ho un'implementazione IDictionary<TKey,TValue>
che contiene internamente n altri Dictionary<TKey, TValue>
e distribuisce tali inserimenti tramite il codice hash della chiave ai sotto-dizionari inviduali. Con 16 sotto-dizionari, il numero di collisioni è piuttosto basso su una macchina a 4 core.
Per inserimenti paralleli, ho bloccato il metodo Add con un ReaderWriterLockSlim
, bloccando solo il singolo dizionario secondario:
public void Add(TKey key, TValue value)
{
int poolIndex = GetPoolIndex(key);
this.locks[poolIndex].EnterWriteLock();
try
{
this.pools[poolIndex].Add(key, value);
}
finally
{
this.locks[poolIndex].ExitWriteLock();
}
}
Quando ho inserito elementi con quattro thread, ho ottenuto solo circa il 32% di utilizzo della CPU e prestazioni scadenti. Quindi ho sostituito ReaderWriterLockSlim con un monitor (ovvero la parola chiave lock
).
L'utilizzo della CPU era ormai quasi al 100% e le prestazioni erano più che raddoppiate.
La mia domanda è: perché è aumentato l'utilizzo della CPU? Il numero di collisioni non dovrebbe essere cambiato. Cosa fa aspettare ReaderWriterLock.EnterWriteLock così tante volte?
Soluzione
Per il caricamento in sola scrittura, il Monitor è più economico di ReaderWriterLockSlim, tuttavia, se si simula il caricamento read + write in cui read è molto più grande di write, ReaderWriterLockSlim dovrebbe eseguire Monitor.
Altri suggerimenti
Non sono un guru, ma la mia ipotesi è che RWLS sia più orientato verso contese pesanti (ad esempio, centinaia di thread) mentre Monitor
è più in sintonia con questi problemi di sincronizzazione una tantum.
Personalmente uso una TimerLock
classe che utilizza Monitor.TryEnter
con un parametro di timeout.
Come fai a sapere cosa ha causato la cattiva prestazione? Non puoi indovinarlo, l'unico modo è fare una sorta di profilazione.
Come gestite il blocco per la raccolta padre o è costante?
Forse devi aggiungere un po 'di output di debug e vedere cosa succede davvero?