C # Sperre mit LINQ-Abfrage

8

Müssen LINQ-Anweisungen wie folgt gesperrt werden? Wenn die Sperre aufgehoben wird, werden alle Ausnahmen abgefangen, wenn mehrere Threads gleichzeitig ausgeführt werden?

%Vor%

PS: Writer -Threads existieren, um das Wörterbuch zu mutieren.

    
Ricky 07.06.2011, 08:39
quelle

4 Antworten

5

Solange die Abfrage keine Nebeneffekte aufweist (z. B. wenn einer der Ausdrücke Code aufruft, der Änderungen vornimmt), muss keine LINQ-Anweisung gesperrt werden.

Grundsätzlich, wenn Sie die Daten nicht ändern (und nichts anderes ändert die Daten, die Sie verwenden), dann brauchen Sie keine Sperren.

Wenn Sie .NET 4.0 verwenden und es ein ConcurrentDictionary gibt, das Thread-sicher ist. Hier ist ein Beispiel für die Verwendung eines Concurrent Dictionary (zugegebenermaßen nicht in einer LINQ-Anweisung)

AKTUALISIEREN

Wenn Sie Daten ändern, müssen Sie Sperren verwenden. Wenn zwei oder mehr Threads versuchen, auf einen gesperrten Codeabschnitt zuzugreifen, tritt ein geringer Leistungsverlust auf, da einer oder mehrere der Threads darauf warten, dass die Sperre aufgehoben wird. HINWEIS: Wenn Sie zu stark sperren, kann es zu schlechteren Ergebnissen kommen, als wenn Sie den Code von Anfang an mit einem sequenziellen Algorithmus erstellt hätten.

Wenn Sie nur Daten lesen, brauchen Sie keine Sperren, da kein veränderbarer gemeinsamer Status zum Schutz vorhanden ist.

Wenn Sie keine Sperren verwenden, kommt es möglicherweise zu zeitweiligen Fehlern, bei denen die Daten nicht ganz stimmen oder bei Kollisionen zwischen Lesern und Schreibern Ausnahmen auftreten. Meiner Erfahrung nach erhalten Sie in den meisten Fällen niemals eine Ausnahme, sondern nur beschädigte Daten (außer Sie wissen nicht unbedingt, dass sie beschädigt sind). Hier ist ein weiteres Beispiel, das zeigt, wie Daten beschädigt werden können, wenn Sie keine Sperren verwenden oder überarbeiten Sie Ihren Algorithmus, um zu bewältigen.

Sie können das Beste aus einem System herausholen, wenn Sie die Zwänge der Entwicklung in einem parallelen System von Anfang an berücksichtigen. Manchmal können Sie Ihren Code neu schreiben, sodass er keine gemeinsamen Daten verwendet. Manchmal können Sie die Daten in Blöcke aufteilen und jeden Thread / Task an seinem eigenen Chunk arbeiten lassen und dann am Ende einen Prozess ausführen, der alles wieder zusammenfügt.

    
Colin Mackay 07.06.2011 08:42
quelle
4

Die meisten Typen sind Thread-sicher zu lesen , aber nicht threadsicher während der Mutation.

Wenn keiner der Threads das Verzeichnis ändert , müssen Sie nichts tun - lesen Sie einfach nur weg.

Wenn jedoch einer der Threads ändert ist, dann haben Sie Probleme und müssen synchronisieren. Der einfachste Ansatz ist lock , dies verhindert jedoch gleichzeitige Leser, auch wenn kein Writer vorhanden ist. Wenn es eine gute Chance gibt, dass Sie mehr Leser als Autoren haben, sollten Sie eine ReaderWriterLockSlim zum Synchronisieren verwenden - dies ermöglicht eine beliebige Anzahl von Lesern (ohne Schreiber) oder: einen Schreiber.

In 4.0 könnten Sie auch ein ConcurrentDictionary<,>

in Betracht ziehen     
Marc Gravell 07.06.2011 08:44
quelle
2

Wenn Ihr Wörterbuch statisch ist und eine Methode, bei der Sie die Abfrage nicht ausführen (oder ein anderer gleichzeitiger Zugriff) und das Wörterbuch von einem anderen Thread geändert werden kann, dann ist eine Sperre erforderlich, andernfalls nicht.

    
abatishchev 07.06.2011 08:41
quelle
1

Ja, Sie müssen Ihre freigegebenen Ressourcen sperren, wenn Sie LINQ in Multithread-Szenarien verwenden (BEARBEITEN: Wenn Ihre Quellcode-Sammlung geändert wird, so wie es Marc sagte, wenn Sie es nur lesen, brauchen Sie das nicht sich darum kümmern). Wenn Sie .Net 4 oder die parallelen Erweiterungen für 3.5 verwenden, können Sie Ihr Wörterbuch durch ein ConcurrentDictionary ersetzen (oder eine andere benutzerdefinierte Implementierung verwenden).

    
Neverbirth 07.06.2011 08:43
quelle