Ich habe folgende Funktion:
//Function to get random number
public static int RandomNumber(int min, int max)
{
Random random = new Random();
return random.Next(min, max);
}
Wie ich es nenne:
byte[] mac = new byte[6];
for (int x = 0; x < 6; ++x)
mac[x] = (byte)(Misc.RandomNumber((int)0xFFFF, (int)0xFFFFFF) % 256);
Wenn ich diese Schleife zur Laufzeit mit dem Debugger mache, erhalte ich unterschiedliche Werte (was ich will). Wenn ich jedoch einen Haltepunkt zwei Zeilen unter diesen Code setze, haben alle Mitglieder des mac
Arrays den gleichen Wert.
Warum passiert das?
new Random().Next((int)0xFFFF, (int)0xFFFFFF) % 256);
ergibt keine besseren "Zufallszahlen" als.Next(0, 256)
Rand.Next(int, int)
Methode, die statischen Zugriff auf zufällige Werte bietet, ohne das Problem der Wiederverwendung vonAntworten:
Jedes Mal, wenn Sie dies tun, wird
new Random()
es mit der Uhr initialisiert. Dies bedeutet, dass Sie in einer engen Schleife oft den gleichen Wert erhalten. Sie sollten eine einzelne Zufallsinstanz beibehalten und Next auf derselben Instanz verwenden.Bearbeiten (siehe Kommentare): Warum brauchen wir
lock
hier ein?Grundsätzlich
Next
wird sich der interne Status derRandom
Instanz ändern . Wenn wir dies gleichzeitig aus mehreren Threads heraus tun, könnten Sie argumentieren, "wir haben das Ergebnis nur noch zufälliger gemacht", aber was wir tatsächlich tun, ist möglicherweise, die interne Implementierung zu brechen, und wir könnten auch anfangen, die gleichen Zahlen zu erhalten von verschiedenen Threads, die möglicherweise ein Problem sein - und vielleicht nicht. Die Garantie dafür, was intern passiert, ist jedoch das größere Problem. daRandom
sich nicht machen keine Garantien für Thread-Sicherheit. Somit gibt es zwei gültige Ansätze:Random
Instanzen pro ThreadBeides kann in Ordnung sein; Das Stummschalten einer einzelnen Instanz von mehreren Anrufern gleichzeitig ist jedoch nur ein Problem .
Das
lock
erreicht den ersten (und einfacheren) dieser Ansätze; Ein anderer Ansatz könnte jedoch sein:Dies ist dann pro Thread, sodass Sie nicht synchronisieren müssen.
quelle
lock (syncObject)
nur, wenn allerandom.Next()
Anrufe auch innerhalb sindlock (syncObject)
. Wenn das Szenario auch mit dem richtigen passiert das Sie beschreiben ,lock
Nutzung, ist es auch extrem geschieht wahrscheinlich in einem Singlethread - Szenario (zBRandom
wird subtil gebrochen).Zur Erleichterung der Wiederverwendung in Ihrer gesamten Anwendung kann eine statische Klasse hilfreich sein.
Sie können dann eine statische Zufallsinstanz mit Code wie verwenden
quelle
Marks Lösung kann sehr teuer sein, da sie jedes Mal synchronisiert werden muss.
Mithilfe des threadspezifischen Speichermusters können wir die Notwendigkeit einer Synchronisierung umgehen:
Messen Sie die beiden Implementierungen und Sie sollten einen signifikanten Unterschied sehen.
quelle
Random
Instanz zum Abrufen des Startwerts ist eine gute Idee. Beachten Sie auch, dass der Code mithilfe derThreadLocal<T>
in .NET 4 eingeführten Klasse (wie Phil auch unten schrieb ) weiter vereinfacht werden kann .Meine Antwort von hier :
Wiederholen Sie einfach die richtige Lösung :
So können Sie anrufen:
alle den ganzen.
Wenn Sie unbedingt eine echte zustandslose statische Methode benötigen , um Zufallszahlen zu generieren, können Sie sich auf a verlassen
Guid
.Es wird ein bisschen langsamer sein, kann aber viel zufälliger sein als
Random.Next
, zumindest aus meiner Erfahrung.Aber nicht :
Die unnötige Objekterstellung wird es insbesondere unter einer Schleife langsamer machen.
Und niemals :
Es ist nicht nur langsamer (innerhalb einer Schleife), seine Zufälligkeit ist ... nun, meiner Meinung nach nicht wirklich gut.
quelle
Random
Klasse entspricht Fall 2 (also auch Fall 1). Sie können nur die Nutzung von ersetzenRandom
durch Ihre ,Guid+Hash
wenn Sie nicht in Fall 2 Fall 1 wahrscheinlich genug, um die Frage zu beantworten , und dann, IhreGuid+Hash
Werke in Ordnung. Aber es ist nicht klar gesagt (ps: diese Uniform )Random
undGuid.NewGuid().GetHashCode()
über Ent ( fourmilab.ch/random ) aus und beide sind ähnlich zufällig.new Random(Guid.NewGuid().GetHashCode())
funktioniert genauso gut wie die Verwendung eines synchronisierten "Masters"Random
zum Generieren von Seeds für "Kinder"Random
. Natürlich hängt es davon ab, wie Ihr System Guids generiert - für mein System sind sie ziemlich zufällig und für andere möglicherweise sogar krypto-zufällig sein. Windows oder MS SQL scheinen heutzutage in Ordnung zu sein. Mono und / oder Mobile können jedoch unterschiedlich sein.GetHashCode
das Guid in .NET wird jedoch aus seiner Zeichenfolgendarstellung abgeleitet. Die Ausgabe ist für meinen Geschmack ziemlich zufällig.Ich würde lieber die folgende Klasse verwenden, um Zufallszahlen zu generieren:
quelle
1) Versuchen Sie, wie Marc Gravell sagte, EINEN Zufallsgenerator zu verwenden. Es ist immer cool, dies dem Konstruktor hinzuzufügen: System.Environment.TickCount.
2) Ein Tipp. Angenommen, Sie möchten 100 Objekte erstellen und annehmen, dass jedes einen eigenen Zufallsgenerator haben sollte (praktisch, wenn Sie in sehr kurzer Zeit LADUNGEN von Zufallszahlen berechnen). Wenn Sie dies in einer Schleife tun würden (Generierung von 100 Objekten), könnten Sie dies folgendermaßen tun (um die vollständige Zufälligkeit sicherzustellen):
Prost.
quelle
Random()
ruftRandom(Environment.TickCount)
trotzdem aufJedes Mal, wenn Sie ausführen
Es spielt keine Rolle, ob Sie es millionenfach ausführen, Sie werden immer den gleichen Startwert verwenden.
Wenn du benutzt
Sie erhalten eine andere Zufallszahlenfolge, wenn ein Hacker den Startwert errät und Ihr Algorithmus mit der Sicherheit Ihres Systems zusammenhängt - Ihr Algorithmus ist fehlerhaft. Ich Sie führen mult. In diesem Konstruktor wird der Startwert von der Systemuhr angegeben. Wenn mehrere Instanzen in einem sehr kurzen Zeitraum (Millisekunden) erstellt werden, ist es möglich, dass sie denselben Startwert haben.
Wenn Sie sichere Zufallszahlen benötigen, müssen Sie die Klasse verwenden
Verwendungszweck:
quelle
It does not matter if you execute it millions of times, you will always use the same seed.
Das stimmt nur, wenn Sie den Samen selbst angeben.Deklarieren Sie einfach die Random-Klassenvariable wie folgt:
Wenn Sie jedes Mal eine andere Zufallszahl aus Ihrer Liste erhalten möchten, verwenden Sie
Jedes Mal durch
Random r = new Random()
einmalige Deklaration .quelle
new Random()
, wird die Systemuhr verwendet. Wenn Sie jedoch den gesamten Code zweimal hintereinander aufrufen, bevor sich die Uhr ändert, erhalten Sie dieselbe Zufallszahl. Das ist der springende Punkt der obigen Antworten.Es gibt viele Lösungen, hier eine: Wenn Sie nur Zahlen möchten, löschen Sie die Buchstaben und die Methode erhält eine zufällige und die Ergebnislänge.
quelle
Random
Instanz, erwarten jedoch weiterhin, dass der Aufrufer eine gemeinsam genutzte Instanz erstellt. Wenn der Aufrufer jedes Mal eine neue Instanz erstellt und der Code zweimal ausgeführt wird, bevor sich die Uhr ändert, erhalten Sie dieselbe Zufallszahl. Diese Antwort macht also immer noch Annahmen, die falsch sein könnten.