Stavo giocando con TPL, e ho cercato di scoprire quanto grande potessi fare leggendo e scrivendo sullo stesso dizionario in parallelo.È possibile che un dizionario in .Net causi un blocco morto durante la lettura e la scrittura in parallelo?
Così ho avuto questo codice:
private static void HowCouldARegularDicionaryDeadLock()
{
for (var i = 0; i < 20000; i++)
{
TryToReproduceProblem();
}
}
private static void TryToReproduceProblem()
{
try
{
var dictionary = new Dictionary<int, int>();
Enumerable.Range(0, 1000000)
.ToList()
.AsParallel()
.ForAll(n =>
{
if (!dictionary.ContainsKey(n))
{
dictionary[n] = n; //write
}
var readValue = dictionary[n]; //read
});
}
catch (AggregateException e)
{
e.Flatten()
.InnerExceptions.ToList()
.ForEach(i => Console.WriteLine(i.Message));
}
}
E 'stato abbastanza incasinato in effetti, ci sono stati un sacco di eccezioni sollevate, per lo più di chiave non esiste, un paio su indice fuori limite di array.
Ma dopo aver eseguito l'applicazione per un po ', si blocca, e la percentuale di CPU rimane al 25%, la macchina ha 8 core. Quindi presumo che siano 2 thread in esecuzione a piena capacità.
Poi corsi dotTrace su di esso, e ha ottenuto questo:
Si abbina la mia ipotesi, due thread in esecuzione al 100%.
Entrambi eseguono il metodo FindEntry del dizionario.
Poi ho eseguito l'applicazione di nuovo, con dotTrace, questa volta il risultato è leggermente diverso:
Questa volta, un thread è in esecuzione FindEntry, l'altro Inserisci.
La mia prima intuizione era che è morto bloccato, ma poi ho pensato che non poteva essere, c'è solo una risorsa condivisa, e non è bloccata.
Quindi, come dovrebbe essere spiegato?
ps: Non sto cercando di risolvere il problema, potrebbe essere risolto utilizzando un ConcurrentDictionary o facendo un'aggregazione parallela. Sto solo cercando una spiegazione ragionevole per questo.
Come puoi immaginare Findentry cerca di individuare una voce. Mantiene alcune variabili locali che cambiano in seguito, il che fa sì che la condizione di fine ciclo non termini mai perché presuppone che il conteggio delle voci che è stato modificato da un altro thread non cambi. –
Quindi non è un blocco morto, ma un ciclo infinito causato dallo stato interno incasinato? – CuiPengFei
sì ........... – pm100