Hier ist der Höhepunkt einer Skeet-Veröffentlichung für einen zufälligen Anbieter :
%Vor%Ich würde gerne das gleiche Konzept in einem .NET 3.5-Projekt verwenden, also ist ThreadLocal keine Option.
Wie würden Sie den Code ändern, um einen thread-sicheren zufälligen Provider ohne die Hilfe von ThreadLocal zu haben?
Ok, ich gehe jetzt mit Simon [ThreadStatic], da ich es am besten verstehe. Viele gute Informationen hier zu überprüfen und zu überdenken, wie es die Zeit erlaubt. Danke allen!
%Vor%Wie würden Sie den Code ändern, um einen thread-sicheren zufälligen Provider ohne die Hilfe von ThreadLocal zu haben?
Jon beantwortet Ihre Frage in dem Artikel, mit dem Sie verlinkt sind:
Verwenden Sie eine Instanz, aber verwenden Sie auch eine Sperre, an die sich jeder Aufrufer beim Verwenden des Zufallszahlengenerators erinnern muss. Das kann vereinfacht werden, indem Sie einen Wrapper verwenden, der das Sperren für Sie übernimmt, aber in einem stark Multithread-System werden Sie möglicherweise weiterhin viel Zeit für das Warten auf Sperren verschwenden.
Sperren Sie es also jedes Mal im Wrapper und entsperren Sie es, wenn Sie fertig sind.
Wenn das billig genug ist, großartig, es ist billig genug.
Wenn das nicht billig genug ist, dann haben Sie zwei Möglichkeiten. Zuerst mache es billiger . Zweitens, schreibe eine threadsafe-Implementierung eines Pseudozufallszahlengenerators, der ohne Sperren verwendet werden kann .
Es gibt eine Reihe von Möglichkeiten, es billiger zu machen. Zum Beispiel könnten Sie Raum für Zeit handeln; Sie könnten beim Start des Programms ein Array aus hunderttausend Zufallszahlen generieren und dann einen Lock-Free-Algorithmus schreiben, der die zuvor berechneten Zufallswerte aus dem Array abruft. Wenn Ihnen die Werte ausgehen, generieren Sie weitere hunderttausend Werte in einem Array und tauschen das neue Array gegen das alte aus.
Das hat den Nachteil, dass sein Speicherverbrauch etwa hunderttausend Mal so groß ist, wie er sein könnte, und dass plötzlich alle hunderttausend Nummern sehr langsam werden und dann wieder schneller werden. Wenn das nicht akzeptabel ist, dann mit einer Strategie, die akzeptabel ist . Du bist derjenige, der weiß, was eine akzeptable Leistung ist und was nicht.
Oder, wie ich schon sagte, schreiben Sie Ihre eigene, wenn Sie die, die für Sie vorgesehen ist, nicht mögen. Schreiben Sie eine ThreadSafe-Implementierung von Random mit akzeptabler Leistung und verwenden Sie sie aus mehreren Threads.
Ich habe gesehen, was Jon über das Sperren des Wrappers gesagt hat, aber nicht sicher, wie der Code aussehen würde!
Etwas wie:
%Vor%Jedes Mal, wenn Sie Next anrufen, nehmen Sie eine Sperre heraus. (Sperren Sie immer ein privates Objekt ; auf diese Weise wissen Sie, dass Ihr Code der einzige Code ist, der sie sperrt!) Wenn zwei Threads Next "zur gleichen Zeit" aufrufen, dann "Verlierer" blockiert, bis der "Gewinner" die Next-Methode verlässt.
Wenn Sie möchten, können Sie das SafeRandom-Objekt sogar zu einer statischen Klasse machen:
%Vor%und jetzt können Sie SafeRandom.Next () von jedem Thread aufrufen.
Ich lese gerade den Link zu "C # in Depth" und, obwohl ich der Tatsache zustimme, dass Random nicht threadsicher ist, ein Schmerz, würde ich tatsächlich einen anderen Ansatz verwenden, um das Problem loszuwerden, nämlich aus Leistungsgründen.
Die Instantiierung einer Zufallsmethode ist eine ziemlich schwere Aktion, deshalb möchte ich nur eine Instanz behalten und sie durch die Verwendung von Sperren threadsicher machen:
%Vor%HTH