Ich habe eine Parallel.ForEach-Schleife, die eine intensive Operation innerhalb des Körpers ausführt.
Die Operation kann eine Hashtable verwenden, um die Werte zu speichern, und kann für andere fortlaufende Schleifenelemente wiederverwendet werden. Ich füge der Hashtabelle hinzu, nachdem die intensive Operation abgeschlossen ist. Das nächste Schleifenelement kann in der Hashtable nachschlagen und das Objekt wiederverwenden, anstatt die intensive Operation erneut auszuführen.
Da ich jedoch Parallel.ForEach verwende, gibt es ein unsicheres Problem, was dazu führt, dass die Hashtable.Add- und ContainsKey (key) -Aufrufe nicht mehr synchron sind, da sie möglicherweise parallel ausgeführt werden. Die Einführung von Sperren kann zu Perf-Problemen führen.
Hier ist der Beispielcode:
%Vor%Es muss eine API geben, Property-Einstellung in der TPL-Bibliothek, die dieses Szenario verarbeiten könnte. Gibt es?
Sie suchen System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>
. Die neuen parallelen Sammlungen verwenden deutlich verbesserte Sperrmechanismen und sollten in parallelen Algorithmen hervorragend funktionieren.
Bearbeiten: Das Ergebnis könnte wie folgt aussehen:
%Vor% Wort der Warnung: Wenn die Elemente in items
nicht alle ein eindeutiges item.Key
haben, dann könnte SomeIntensiveOperation
zweimal für diesen Schlüssel aufgerufen werden. Im Beispiel wird der Schlüssel nicht an SomeIntensiveOperation
übergeben, aber es bedeutet, dass der Code "Etwas mit Wert ausführen" die Paare key / valueA und key / valueB ausführen könnte und nur ein Ergebnis im Cache gespeichert würde (nicht notwendigerweise der erste von SomeIntensiveOperation entweder). Du brauchst eine parallele Lazy-Factory, um das Problem zu lösen. wenn es ein Problem ist. Aus naheliegenden Gründen sollte SomeIntensiveOperation Thread-sicher sein.
Überprüfen Sie den System.Collections.Concurrent -Namespace Ich denke, dass Sie ConcurrentDictionary
benötigenVerwenden Sie einen ReaderWriterLock, dies hat eine gute Leistung für Arbeiten, die viele Lesevorgänge und wenige Schreibvorgänge von kurzer Dauer haben. Ihr Problem scheint dieser Spezifikation zu entsprechen.
Alle Leseoperationen laufen schnell und sind frei, die einzige Zeit, die jemand blockiert wird, ist, wenn ein Schreibvorgang stattfindet, und dieser Schreibvorgang ist nur so lang wie es dauert, um etwas in eine Hashtable zu schieben.
Ich denke, ich werde etwas Code wegwerfen ...
%Vor%Ich sehe keine andere richtige Wahl, als (mehr oder weniger explizite) Sperren zu verwenden (eine synchronisierte Hashtabelle überschreibt einfach alle Methoden mit Sperren).
Eine weitere Option könnte sein, dass das Wörterbuch nicht mehr synchron läuft. Die Racebedingung wird das Wörterbuch nicht beschädigen, es wird lediglich der Code benötigt, um einige überflüssige Berechnungen durchzuführen. Profilieren Sie den Code, um zu prüfen, ob die Sperre oder die fehlende Memoisierung schlechtere Auswirkungen hat.
Tags und Links .net c# task-parallel-library parallel-extensions