Warten mehrere Threads auf denselben Lock, um auf dieselben Daten zuzugreifen, läuft trotz zusätzlicher Threads immer nur einer zur Zeit.
Warum Mehrere Threads greifen gleichzeitig auf gemeinsame Daten zu, etwa Auktionshaus oder Gildenbank → Folge Bis der Thread mit dem Lock fertig ist, warten alle anderen → Auf dem Bildschirm Nur bestimmte Funktionen langsam, im schlimmsten Fall verzögert sich der gesamte Tick
Locks feingranularer aufteilen, Arbeit innerhalb von Locks reduzieren, nachrichtenbasierte Architektur (für alle Daten einen zuständigen Thread festlegen, andere Threads schicken nur Anfragen per Nachricht).
Größenordnungen
Macht die Arbeit innerhalb des Locks 20 % der Gesamtarbeit aus, erreicht der Durchsatz egal mit wie vielen Threads höchstens das 5-Fache eines einzelnen Threads. Bei 40 % ist beim 2,5-Fachen Schluss.
Im Graphen
Steigt mit Spielerzahl und Last · Verarbeitungszeit der Anfragen, CPU und Kontextwechsel pro Thread
Wo nachsehen
Mit pidstat -w -t 1 die freiwilligen Kontextwechsel pro Thread prüfen (cswch/s: wie oft ein Thread anhält, um auf eine Ressource zu warten), mit bcc offcputime -p ermitteln, wo Threads außerhalb der CPU warten (Wartezeit pro Call-Stack). Bei .NET die Zahl der Lock-Contentions in dotnet-counters (ab .NET 9 dotnet.monitor.lock_contentions, bis 8 Monitor Lock Contention Count)
Spricht dafür
Mit steigender Last bleibt die CPU-Auslastung niedrig, die Verarbeitungszeit wächst aber, der Großteil der Wartezeit entfällt auf Call-Stacks, die einen Lock anfordern, und die Zahl der Lock-Contentions steigt mit
Spricht dagegen
CPU voll ausgelastet: Problem der Rechenlast (überschrittenes Tick-Budget, überlastetes Gebiet auf einem einzelnen Thread). Gewartet wird auf DB- oder Dateiaufrufe: eher synchrone Aufrufe im Game-Thread
Prüfmittel
Mit Infrastruktur-Tools prüfbar (ohne Spielcode)
Mehr dazu
Das tritt in Architekturen auf, in denen mehrere Threads gemeinsam Spieldaten ändern. Ist für jedes Gebiet und jede Funktion ein einzelner Thread zuständig und läuft der Austausch nur über Nachrichten, gibt es kaum Locks. Dafür muss man darauf achten, dass sich die Arbeit nicht auf einem Thread ballt (überlastetes Gebiet auf einem einzelnen Thread). Wartet der Game-Thread auf einen Lock, den ein langsamer Speichervorgang hält, steht der ganze Tick still.
Amdahl's Law in the Multicore EraIEEE Artikel in IEEE Computer 2008 (Autorenfassung). Ist der nicht parallelisierbare Anteil 1−f, kann der Speedup egal mit wie vielen Kernen 1/(1−f) nicht überschreiten (Amdahlsches Gesetz)
Request schedulingMicrosoft Grains (Actors) in Orleans arbeiten Anfragen nach einem Single-Thread-Ausführungsmodell einzeln bis zum Ende ab und ändern ihren Zustand daher nie gleichzeitig, warten Grains gegenseitig auf ihre Antworten, ist ein Deadlock möglich
pidstat(1) — Linux manual pagesysstat cswch/s bei -w ist die Zahl freiwilliger Kontextwechsel, bei denen ein Thread anhält, um auf eine Ressource zu warten, -t zeigt die Werte pro Thread
Well-known EventCounters in .NETMicrosoft Monitor Lock Contention Count (monitor-lock-contention-count): Zahl der Konflikte beim Versuch, einen Monitor-Lock zu erhalten
.NET runtime metrics.NET Ab .NET 9 dotnet.monitor.lock_contentions: Zahl der Konflikte beim Versuch, einen Monitor-Lock zu erhalten, seit Prozessstart