Ich habe mit Collections und Threading gespielt und bin auf die raffinierten Erweiterungsmethoden gestoßen, die die Leute geschaffen haben, um die Verwendung von ReaderWriterLockSlim zu erleichtern, indem sie das IDisposable-Muster erlauben.
Ich glaube jedoch, dass ich erkannt habe, dass etwas in der Implementierung ein Performance-Killer ist. Mir ist klar, dass Erweiterungsmethoden die Leistung nicht wirklich beeinflussen sollen, also nehme ich an, dass etwas in der Implementierung die Ursache ist ... die Menge der geschaffenen / gesammelten Einwegstrukturen?
Hier ist ein Testcode:
%Vor%Hier ist ein typisches Ergebnis:
%Vor% Wie Sie sehen, macht die Verwendung der Erweiterungen tatsächlich die Leistung SCHLECHTER als nur die Verwendung von lock
(Monitor).
Sieht so aus, als wäre es der Preis für die Instanziierung von Millionen von Strukturen und das zusätzliche bisschen von Invokationen.
Ich würde so weit gehen, zu sagen, dass der ReaderWriterLockSlim in diesem Beispiel missbraucht wird, eine Sperre ist in diesem Fall gut genug und die Performance-Kante, die Sie mit dem ReaderWriterLockSlim bekommen, ist vernachlässigbar im Vergleich zu dem Preis, diese Konzepte Junior zu erklären Entwickler.
Sie erhalten einen großen Vorteil mit Locks im Reader-Writer, wenn die Lese- und Schreibvorgänge nicht vernachlässigbar lang sind. Der Boost wird am größten sein, wenn Sie ein System haben, das hauptsächlich auf Leseoperationen basiert.
Versuchen Sie, ein Thread.Sleep (1) einzufügen, während die Sperren erfasst werden, um zu sehen, wie groß der Unterschied ist.
Siehe diesen Benchmark:
%Vor%In meinem Benchmarking merke ich nicht viel von einem Unterschied zwischen den beiden Stilen, ich würde mich wohl fühlen, wenn ich es benutze, vorausgesetzt, es hat einen Finalizer-Schutz, falls die Leute vergessen, zu entsorgen ....
%Vor% Der Code scheint eine Struktur zu verwenden, um den Overhead der Objekterstellung zu vermeiden, führt jedoch nicht die anderen notwendigen Schritte aus, um diesen Lightweight zu erhalten. Ich glaube, dass es den Rückgabewert von ReadLock
enthält, und wenn dies der Fall ist, negiert der gesamte Vorteil der Struktur. Dies sollte alle Probleme beheben und genauso gut funktionieren, als würde man die IDisposable
-Schnittstelle nicht durchlaufen.
Edit: Benchmarks gefordert. Diese Ergebnisse sind normalisiert, so dass die manuelle -Methode (Aufruf Enter
/ ExitReadLock
und Enter
/ ExitWriteLock
inline mit dem geschützten Code) einen Zeitwert von 1,00 hat. Die ursprüngliche Methode ist langsam, da sie Objekte auf dem Heap zuweist, die die manuelle Methode nicht verwendet. Ich habe dieses Problem behoben, und im Freigabemodus geht sogar der Overhead der Erweiterungsmethode weg, wodurch er genauso schnell ist wie die manuelle Methode.
Debug Build:
%Vor%Build freigeben:
%Vor%Mein Code:
%Vor%Meine Vermutung (Sie müssten ein Profil erstellen, um es zu überprüfen) besteht darin, dass der Leistungsabfall nicht vom Erstellen der Wegwerf-Instanzen herrührt (sie sollten ziemlich billig sein und Strukturen sein). Stattdessen erwarte ich, dass die Action-Delegierten erstellt werden. Sie könnten versuchen, die Implementierung Ihrer Disposable-Struktur zu ändern, um die Instanz von ReaderWriterLockSlim zu speichern, anstatt einen Aktionsdelegaten zu erstellen.
Bearbeiten: @ 280Z28s Beitrag bestätigt, dass es die Heap-Zuweisung von Action-Delegaten ist, die die Verlangsamung verursacht.
Tags und Links c# multithreading performance locking extension-methods