Einfache thread-sichere Zufallswerte in C# – Ein tiefer Einblick mit Tim Corey
Die Erzeugung zufälliger Zahlen gehört zu den Aufgaben, auf die jeder Entwickler stößt. Auch wenn die Erstellung eines einfachen Zufallswertes trivial erscheinen mag, kann die Gewährleistung der Thread-Sicherheit in C#, insbesondere in Multi-Thread-Umgebungen, knifflig sein. In seinem Video "Einfache thread-sichere Zufallswerte in C#" untersucht Tim Corey, wie zufällige Zahlen in C# funktionieren, die Fallstricke älterer Methoden und wie man bei der Arbeit mit mehreren Threads Thread-Sicherheit erreicht.
In diesem Artikel werden wir Tims Erklärung folgen und bieten einen detaillierten Blick auf die thread-sichere Zufallszahlengenerierung, bewährte Praktiken und zugehörige Synchronisationstechniken.
Introduction to Random Values and Thread Safety in C
Tim beginnt damit zu betonen, dass die Erzeugung zufälliger Werte in C# im Allgemeinen einfach ist. Es gibt jedoch verschiedene Möglichkeiten, Dinge zu tun, und die Wahl hängt davon ab, ob Ihr Code in einem Thread oder mehreren Threads gleichzeitig ausgeführt wird. Tim betont, dass dieses Video als schneller, praxisorientierter Leitfaden für Entwickler gedacht ist, der sowohl einfache Beispiele als auch tiefere Einblicke in die Thread-Sicherheit bietet.
Er demonstriert seine Beispiele in einer Konsolenanwendung unter Verwendung von Visual Studio 2026 Preview mit .NET 10, beruhigt jedoch die Zuschauer, dass der gleiche Code in Visual Studio 2022 und .NET 9 funktioniert. Für diejenigen, die mitkommen möchten, stellt Tim den Quellcode in der Beschreibung zur Verfügung.
Traditional Random Number Generation in C
Tim zeigt zunächst den klassischen Ansatz zur Erzeugung zufälliger Zahlen mit der Random-Klasse. Er erstellt zwei Instanzen, RNG1 und RNG2, und demonstriert das Erzeugen zufälliger Ganzzahlen mit Next().
Random rng1 = new();
Random rng2 = new();
for(int i = 0; i < 10; i++)
{
int output1 = rng1.Next(1, 101);
int output2 = rng2.Next(1, 101);
Console.WriteLine($"Zufall 1: {output1}, Zufall 2: {output2}");
}
Tim erklärt, dass die Ausführung dieses Codes unterschiedliche Zahlen für jede Instanz erzeugt, aber dieser Code ist nicht thread-sicher. In einer Multi-Thread-Umgebung können unerwartete Werte oder Duplikate auftreten, wenn zwei Threads auf dieselbe Random-Instanz zugreifen, da der interne Zustand des Random-Objekts möglicherweise gleichzeitig abgerufen wird.
Er weist darauf hin, dass eine Möglichkeit zur Gewährleistung der Thread-Sicherheit darin besteht, für jeden Thread eine Random-Instanz zu verwenden. Das ist wichtig für Worker-Threads, asynchrone Methoden oder jede Situation, bei der mehrere Threads Code gleichzeitig ausführen können. Das Teilen der gleichen Instanz über Threads hinweg ohne ordnungsgemäße Synchronisation kann zu Wettlaufsituationen, falschen Werten oder sogar zu einem Deadlock führen, wenn es nicht ordnungsgemäß verwaltet wird.
Die Verwendung eines Seed für vorhersehbare Zufallszahlen
Tim demonstriert dann die Verwendung eines Seed. Ein Seed ist ein Anfangswert, der die erzeugte Zahlenfolge bestimmt. Zum Beispiel bei der Verwendung eines Seed von 25 für sowohl RNG1 als auch RNG2:
Random rng1 = new(25);
Random rng2 = new(25);
Beide Instanzen erzeugen die gleiche Sequenz von Zahlen. Tim betont, dass dies ein Feature ist und kein Fehler, und in Szenarien nützlich ist, in denen Reproduzierbarkeit erforderlich ist. Dies kann bei Unit-Tests oder beim Debuggen eines Multi-Thread-Programms hilfreich sein, bei dem Sie eine Sequenz von Zufallswerten über zwei oder mehr Threads hinweg reproduzieren müssen.
Thread-sichere Zufallszahlen mit Random.Shared
Tim stellt Random.Shared vor, eine moderne, thread-sichere Methode, um Zufallszahlen zu erzeugen. Im Gegensatz zur manuellen Erstellung von Instanzen ist Random.Shared eine statische, gemeinsam genutzte Ressource, die den gleichzeitigen Zugriff automatisch handhabt:
int output1 = Random.Shared.Next();
int output2 = Random.Shared.Next();
Mit diesem Ansatz müssen Sie sich keine Sorgen über Sperren, statische Konstrukteure oder gemeinsam genutzte Ressourcen machen. Die in .NET eingebauten thread-sicheren Sammlungen und die Random.Shared-Instanz machen es sicher, mehrere Threads gleichzeitig zu verwenden.
Vorteile von Random.Shared
Tim erklärt mehrere Vorteile dieses Ansatzes:
-
Keine Instanziierung erforderlich: Sie benötigen keine separaten Instanzen für jeden Thread.
-
Standardmäßig Thread-sicher: Sicher in parallelen Aufgaben oder Worker-Threads zu verwenden.
- Einfache API: Unterstützt Ganzzahlen, Dezimalzahlen und sogar das Mischen von Arrays.
Er weist auf eine Einschränkung hin: Sie können keine Samen setzen, was bedeutet, dass die Sequenzen nicht vorhersagbar sind. Für Szenarien, in denen dieselbe Reihenfolge von Zahlen über mehrere Abläufe hinweg benötigt wird, sollten Sie weiterhin individuelle Instanzen mit einem Samen verwenden.
Thread-Sicherheit in komplexem Code gewährleisten
Obwohl Random.Shared intern die Thread-Sicherheit handhabt, ermöglichen Tims Beispiele uns, allgemeine Techniken der Thread-Sicherheit in C# zu diskutieren. In komplexerem Code oder multi-threaded Umgebungen müssen Sie häufig korrekt synchronisieren, um Race Conditions zu vermeiden und die Datenintegrität sicherzustellen. Einige gängige Techniken sind:
-
Lock-Anweisung: Verhindert, dass mehrere Threads gleichzeitig auf einen kritischen Abschnitt zugreifen.
-
Statische Mitglieder und statische Konstrukteure: Können verwendet werden, um gemeinsam genutzte Ressourcen sicher zu initialisieren.
-
Thread-sichere Sammlungen: Klassen wie ConcurrentQueue, ConcurrentStack und ConcurrentDictionary ermöglichen einen sicheren gleichzeitigen Zugriff.
- Gegenseitiger Ausschluss (Mutex/Monitor): Gewährleistet, dass nur ein Thread gleichzeitig einen Abschnitt des Codes ausführen kann.
Tim erklärt, dass in den meisten Fällen für Zufallszahlen, Random.Shared die Notwendigkeit für diese Techniken beseitigt, aber in Multi-Thread-Anwendungen mit gemeinsam genutzten Ressourcen sind diese Methoden unerlässlich, um Deadlocks und unerwartete Werte zu vermeiden.
Praktische Richtlinien von Tim Corey
Tim gibt klare Anweisungen zur sicheren Verwendung von Zufallszahlen in Multi-Thread-Anwendungen:
-
Verwenden Sie Random.Shared für Einfachheit: Ideal, wenn Sie nur einen Zufallswert brauchen und die Leistung wichtig ist.
-
Verwenden Sie instanzierte Samen für Reproduzierbarkeit: Notwendig, wenn Sie die gleichen Daten verfolgen oder in Multi-Thread-Umgebungen debuggen.
-
Vermeiden Sie Random in der Kryptografie: Für Sicherheit verwenden Sie stattdessen kryptografische Bibliotheken.
- Verstehen Sie die Grundlagen der Thread-Sicherheit: Wissen Sie, wann Ihr Code von mehreren Threads zugegriffen wird und implementieren Sie Synchronisation nur bei Bedarf.
Er beruhigt Entwickler, dass Random.Shared selbst dann funktioniert, wenn Millionen von Aufrufen pro Millisekunde von mehreren Threads getätigt werden und er den gleichzeitigen Zugriff effizient handhabt.
Conclusion: Safe and Simple Random Numbers in C
Tim Coreys Video zeigt, dass das Erzeugen von thread-sicheren Zufallszahlen in C# einfacher ist, als viele Entwickler ahnen. Durch die Verwendung von Random.Shared können Sie viele Fallgruben vermeiden, die mit Multi-Thread-Umgebungen verbunden sind. Für Fälle, in denen vorhersagbare Sequenzen notwendig sind, bietet die Verwendung individueller Instanzen mit einem Samen einen zuverlässigen Ansatz.
Das Verständnis von Thread-Sicherheit, kritischen Abschnitten und Synchronisationstechniken stellt sicher, dass Ihr Code korrekt bleibt und sich in Multi-Thread-Anwendungen gut verhält. Unter Beachtung von Tims Anleitung können Entwickler sicher Code schreiben, der thread-sicher für Worker-Threads, asynchrone Methoden und parallele Aufgaben ist, ohne sich Gedanken über Race Conditions, Deadlocks oder unerwartete Werte machen zu müssen.
