Gleichzeitige Verwendung des Wörterbuchs

83

Habe ich Recht, wenn ich denke, dass dies die richtige Verwendung eines Concurrent Dictionary ist?

private ConcurrentDictionary<int,long> myDic = new ConcurrentDictionary<int,long>();

//Main thread at program startup

for(int i = 0; i < 4; i++)
{
  myDic.Add(i, 0);
}

//Seperate threads use this to update a value

myDic[InputID] = newLongValue;

Ich habe keine Sperren usw. und aktualisiere nur den Wert im Wörterbuch, obwohl möglicherweise mehrere Threads versuchen, dasselbe zu tun.

Jon
quelle
2
Es kommt darauf an - hängt newLongValuevom vorherigen Wert von ab myDic[InputID]?
Damien_The_Unbeliever
3
Sie sollten es vermeiden, mit dem Schlüssel direkt myDic[InputID]auf die Rennbedingungen zuzugreifen . Sie sollten versuchenGetOrAdd
Olivier Albertini
3
@OlivierAlbertini, ich glaube nicht, myDic[InputID]dass es Probleme gibt, wenn es als Wert verwendet wird. GetOrAddist kein korrekter Ersatz, da er nur hinzugefügt wird, wenn kein Wert vorhanden ist. Wir können stattdessen verwenden AddOrUpdate, um denselben Wert im Wörterbuch hinzuzufügen / zu aktualisieren.
Jatin Sanghvi

Antworten:

74

Es hängt davon ab, was Sie unter threadsicher verstehen.

Von MSDN - Gewusst wie: Hinzufügen und Entfernen von Elementen zu einem ConcurrentDictionary :

ConcurrentDictionary<TKey, TValue>ist für Multithread-Szenarien ausgelegt. Sie müssen in Ihrem Code keine Sperren verwenden, um Elemente zur Sammlung hinzuzufügen oder daraus zu entfernen. Es ist jedoch immer möglich, dass ein Thread einen Wert abruft und ein anderer Thread die Sammlung sofort aktualisiert, indem er demselben Schlüssel einen neuen Wert gibt.

So ist es möglich, eine inkonsistente Ansicht des Werts eines Elements im Wörterbuch zu erhalten.

Oded
quelle
2
Das ist ein interessanter Punkt! Würden Sie in diesem Szenario immer noch eine Sperre verwenden?
Jon
@ Jon - Es hängt von Ihrer Bewerbung ab und ob das in Ordnung ist. Aber ich würde sagen, wenn Sie konsistente Ansichten von Elementen wünschen, müssten Sie jedes Lesen und Aktualisieren eines Elements in ein Schloss einschließen.
Oded
12
Ich denke, das sagt der Arzt nicht. Die Inkonsistenz hat mit dem zu tun, was die Ansicht enthält. Wenn die Ansicht nur der Wert ist, ist sie vollkommen konsistent. Solange Sie den Wert eines Schlüssels erhalten, kann sich der Wert des Schlüssels im Wörterbuch ändern. Dies ist so inkonsistent wie der Wert DateTime.Now.
George Mavritsakis
4

Der beste Weg, dies herauszufinden, ist die Überprüfung der MSDN-Dokumentation.

Für ConcurrentDictionary lautet die Seite http://msdn.microsoft.com/en-us/library/dd287191.aspx

Im Abschnitt Thread-Sicherheit heißt es: "Alle öffentlichen und geschützten Mitglieder von ConcurrentDictionary (Of TKey, TValue) sind threadsicher und können von mehreren Threads gleichzeitig verwendet werden."

Aus Sicht der Parallelität sind Sie also in Ordnung.

Erdem
quelle
2

Ja, du hast recht.

Dies und die Möglichkeit, das Wörterbuch in einem Thread aufzulisten, während es in einem anderen Thread geändert wird, sind die einzigen Existenzmittel für diese Klasse.

Jan.
quelle
9
Was ich hinzufügen möchte, ist, dass hier hilfreiche Informationen darüber, wie und wann zu verwenden ist ConcurrentDictionary.
Alex.b
1

Es kommt darauf an, in meinem Fall bevorzuge ich diese Methode.

ConcurrentDictionary<TKey, TValue>.AddOrUpdate Method (TKey, Func<TKey, TValue>, Func<TKey, TValue, TValue>);

Einzelheiten zur Methodenverwendung finden Sie in der MSDN-Bibliothek .

Beispielnutzung:

results.AddOrUpdate(
  Id,
  id => new DbResult() {
     Id = id,
     Value = row.Value,
     Rank = 1
  },
  (id, v) =>
  {
     v.Rank++;
     return v;
  });
Onur
quelle
2
Zu Ihrer Information: "Wenn Sie eine Value Factory-Methode (für die Methoden GetOrAdd und AddOrUpdate) angeben, kann sie tatsächlich ausgeführt werden und das Ergebnis wird anschließend verworfen (weil ein anderer Thread das Rennen gewonnen hat)." Weitere Infos hier: arbel.net/2013/02/03/…
keremispirli
Ja, Sie haben Recht, wie im Abschnitt "Wenn Sie AddOrUpdate gleichzeitig in verschiedenen Threads aufrufen, wird addValueFactory möglicherweise mehrmals aufgerufen, aber das Schlüssel / Wert-Paar wird möglicherweise nicht bei jedem Aufruf zum Wörterbuch hinzugefügt." Sie müssen also sicherstellen, dass Sie nicht mehrere persistente Objekte generieren.
Onur
Wenn Sie Inhalte aktualisieren und das gespeicherte Objekt nicht vollständig ändern müssen, z. B. um eine Eigenschaft eines zuvor hinzugefügten Objekts zu ändern, ist diese Methode hilfreich, andernfalls müssen Sie Sperren oder andere Synchronisationsmethoden verwenden.
Onur
1

Nur eine Anmerkung: Rechtfertigt nicht die Verwendung eines ConcurrentDicitonary- Objekts mit einer linearen Schleife, wodurch es nicht ausreichend genutzt wird. Die beste Alternative besteht darin, den Empfehlungen der Microsoft-Dokumentation zu folgen, die von Oded mithilfe von Parallelität gemäß dem folgenden Beispiel erwähnt wurden:

Parallel.For(0, 4, i => 
{
   myDic.TryAdd(i, 0);
});
Antonio Leonardo
quelle