Verwenden einer Hashtabelle innerhalb einer Parallel.ForEach?

7

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?

    
Vin 01.11.2009, 18:20
quelle

4 Antworten

18

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.

    
Sam Harwell 01.11.2009, 18:41
quelle
4

Überprüfen Sie den System.Collections.Concurrent -Namespace Ich denke, dass Sie ConcurrentDictionary

benötigen     
Hannoun Yassir 01.11.2009 18:42
quelle
3

Verwenden 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.

ReaderWriterLockSlim auf MSDN

Ich denke, ich werde etwas Code wegwerfen ...

%Vor%     
joshperry 01.11.2009 18:42
quelle
1

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.

    
Dario 01.11.2009 18:33
quelle