Il concetto di locks di lettura-scrittura è semplice, permettendo a più thread di acquisire lock di lettura contemporaneamente, ma solo un thread è autorizzato a ottenere lock di scrittura contemporaneamente, quindi viene chiamato anche locks shared-exclusive. In C#, si consiglia di utilizzare la classe ReaderWriterLockSlim per completare la funzione di blocco lettura/scrittura. In alcuni casi, il numero di letture di un oggetto è molto maggiore del numero di modifiche e, se viene semplicemente bloccato tramite bloccaggio, ciò influirà sull'efficienza della lettura. Se viene utilizzato un blocco di lettura-scrittura, più thread possono leggere l'oggetto contemporaneamente, e sarà bloccato solo quando l'oggetto è occupato dal blocco di scrittura. In parole semplici, quando un thread entra in modalità lettura, gli altri thread possono comunque entrare in modalità lettura, assumendo che un thread voglia entrare in modalità scrittura in quel momento, quindi deve essere bloccato. fino a quando la modalità lettura non esce. Allo stesso modo, se un thread entra in modalità scrittura, gli altri thread saranno bloccati sia che vogliano scrivere che leggere. Ci sono 2 modi per entrare in modalità scrittura/lettura: EnterReadLock tenta di entrare nello stato di blocco della modalità scrittura. TryEnterReadLock(Int32) tenta di entrare nello stato di blocco in modalità lettura, con l'opzione di selezionare un timeout intero. EnterWriteLock tenta di entrare nello stato di blocco Write Mode. TryEnterWriteLock(Int32) tenta di entrare nello stato di blocco della modalità scrittura, e il timeout può essere selezionato. Ci sono 2 modi per uscire dalla modalità scrittura/lettura: ExitReadLock riduce il conteggio ricorsivo della modalità di lettura ed esce dalla modalità di lettura quando il conteggio risultante è 0 (zero). ExitWriteLock riduce il conteggio ricorsivo del pattern di scrittura ed esce dalla modalità di scrittura quando il conteggio risultante è 0 (zero). Ecco come usarlo:
Puoi vedere che il thread 3 e il thread 4 possono entrare in modalità lettura contemporaneamente, mentre il thread 5 può entrare in modalità scrittura dopo 5 secondi (cioè dopo che i thread 3 e 4 sono usciti dal blocco di lettura). Modifica il codice sopra, prima apri 2 thread in modalità scrittura, poi apri i thread in modalità lettura, il codice è il seguente:
I risultati sono i seguenti:
Come puoi vedere, il thread 3 e il thread 4 entrano entrambi in modalità scrittura, ma il thread 3 occupa prima il blocco di scrittura, quindi il thread 4 deve aspettare 10 secondi prima di entrare. I thread 5 e 6 devono occupare il blocco di lettura, quindi aspetta che il thread 4 esca dal blocco di scrittura prima di continuare. TryEnterReadLock e TryEnterWriteLock possono impostare un timeout; quando si esegue questa frase, il thread si bloccherà qui; se il blocco può essere occupato in questo momento, allora return true, se il timeout non ha ancora occupato il lock, allora return false, rinuncia all'occupazione del lock e continuerà a eseguire direttamente il codice seguente. EnterUpgradeableReadLock La classe ReaderWriterLockSlim offre una modalità di lettura aggiornabile, che si differenzia dalla modalità di lettura in quanto può anche essere aggiornata alla modalità scrittura chiamando i metodi EnterWriteLock o TryEnterWriteLock. Perché solo un thread può essere in modalità aggiornabile alla volta. Un thread che entra in modalità upgradable non influenzerà il thread in modalità lettura, cioè quando un thread entra in modalità upgradable, un numero qualsiasi di thread può entrare in modalità lettura contemporaneamente senza bloccare. Se più thread sono già in attesa di acquisire un blocco di scrittura, eseguire EnterUpgradeableReadLock bloccherà finché quei thread non esauriscono o non esce dal blocco di scrittura. Il seguente codice mostra come aggiornare a un blocco di scrittura in modalità di lettura aggiornabile.
L'impatto dei blocchi di lettura/scrittura sulle prestazioni è evidente. Il seguente codice di prova:
Il codice sopra simula il funzionamento di 500 Task, ognuno dei quali occupa un thread pool di thread, di cui 20 sono thread di scrittura e 480 thread di lettura sono simulati. Ci vogliono 10 ms per leggere i dati e 100 ms per scrivere per testare rispettivamente il metodo lock e il metodo ReaderWriterLockSlim. Si può fare una stima, per ReaderWriterLockSlim, assumendo che 480 thread leggano contemporaneamente, allora consumano 10ms, 20 operazioni di scrittura occupano 2000ms, quindi il tempo consumato è 2010ms, e per il metodo di blocco ordinario, poiché sono tutti esclusivi, quindi 480 operazioni di lettura occupano 4800ms + 20 operazioni di scrittura 2000ms = 6800ms. I risultati hanno mostrato un miglioramento delle prestazioni evidente.
|