Der übliche Ansatz, mehrere Kerne auszunutzen, ist offen gesagt einfach falsch. Wenn Sie Ihre Subsysteme in verschiedene Threads unterteilen, wird ein Teil der Arbeit zwar auf mehrere Kerne verteilt, es treten jedoch einige schwerwiegende Probleme auf. Erstens ist es sehr schwer, damit zu arbeiten. Wer möchte sich mit Sperren, Synchronisierung, Kommunikation und anderen Dingen beschäftigen, wenn er stattdessen einfach nur Rendering- oder Physik-Code schreiben könnte? Zweitens skaliert der Ansatz nicht wirklich. Bestenfalls können Sie so drei oder vier Kerne ausnutzen, und das ist, wenn Sie wirklich wissen, was Sie tun. Es gibt nur so viele Subsysteme in einem Spiel, und von diesen gibt es noch weniger, die viel CPU-Zeit in Anspruch nehmen. Es gibt ein paar gute Alternativen, die ich kenne.
Einer ist, einen Haupt-Thread zusammen mit einem Worker-Thread für jede zusätzliche CPU zu haben. Unabhängig vom Subsystem delegiert der Haupt-Thread isolierte Aufgaben über eine oder mehrere Warteschlangen an die Worker-Threads. Diese Aufgaben können selbst noch andere Aufgaben erzeugen. Der einzige Zweck der Worker-Threads besteht darin, die einzelnen Aufgaben nacheinander aus der Warteschlange zu holen und auszuführen. Das Wichtigste ist jedoch, dass ein Thread, sobald er das Ergebnis einer Aufgabe benötigt, das Ergebnis erhalten kann, wenn die Aufgabe abgeschlossen ist. Andernfalls kann er die Aufgabe sicher aus der Warteschlange entfernen und die Aufgabe ausführen Aufgabe selbst. Das heißt, nicht alle Aufgaben werden parallel zueinander geplant. Es ist gut, mehr Aufgaben zu haben, als gleichzeitig ausgeführt werden könnenwas in diesem Fall; Dies bedeutet, dass es wahrscheinlich skaliert, wenn Sie weitere Kerne hinzufügen. Ein Nachteil dabei ist, dass das Entwerfen einer anständigen Warteschlange und einer Worker-Schleife im Voraus viel Arbeit erfordert, es sei denn, Sie haben Zugriff auf eine Bibliothek oder eine Sprachlaufzeit, die dies bereits für Sie bereitstellt. Am schwierigsten ist es, sicherzustellen, dass Ihre Aufgaben wirklich isoliert und threadsicher sind und dass Ihre Aufgaben in einem glücklichen Mittelfeld zwischen grobkörnig und feinkörnig liegen.
Eine andere Alternative zu Subsystem-Threads besteht darin, jedes Subsystem isoliert zu parallelisieren. Das heißt, anstatt Rendering und Physik in ihren eigenen Threads auszuführen, schreiben Sie das Physik-Subsystem so, dass alle Ihre Kerne gleichzeitig verwendet werden. Schreiben Sie das Rendering-Subsystem so, dass alle Ihre Kerne gleichzeitig verwendet werden. abhängig von anderen Aspekten Ihrer Spielarchitektur). Im Physik-Subsystem können Sie beispielsweise alle Punktmassen im Spiel nehmen, sie auf Ihre Kerne aufteilen und dann alle Kerne gleichzeitig aktualisieren lassen. Jeder Kern kann dann Ihre Daten in engen Schleifen mit guter Lokalität bearbeiten. Dieser Lock-Step-Parallelitätsstil ähnelt dem einer GPU. Das Schwierigste dabei ist, sicherzustellen, dass Sie Ihre Arbeit in feinkörnige Stücke aufteilen, sodass sie gleichmäßig verteilt wirdtatsächlich führt zu einer gleichen Menge Arbeit auf alle Prozessoren.
Manchmal ist es jedoch aufgrund der Politik, des vorhandenen Codes oder anderer frustrierender Umstände am einfachsten, jedem Subsystem einen Thread zuzuweisen. In diesem Fall ist es am besten zu vermeiden, mehr Betriebssystem-Threads als Kerne für CPU-schwere Workloads zu erstellen (wenn Sie eine Laufzeit mit Lightweight-Threads haben, die sich zufällig über Ihre Kerne verteilen, ist dies keine so große Sache). Vermeiden Sie außerdem übermäßige Kommunikation. Ein guter Trick ist, Pipelining zu versuchen. Jedes wichtige Subsystem kann gleichzeitig an einem anderen Spielstatus arbeiten. Pipelining reduziert den Kommunikationsaufwand zwischen Ihren Subsystemen, da nicht alle gleichzeitig auf dieselben Daten zugreifen müssen, und es kann auch einige der durch Engpässe verursachten Schäden aufheben. Zum Beispiel, Wenn die Fertigstellung Ihres Physik-Subsystems in der Regel sehr lange dauert und Ihr Rendering-Subsystem immer darauf wartet, kann Ihre absolute Bildrate höher sein, wenn Sie das Physik-Subsystem für das nächste Bild ausführen, während das Rendering-Subsystem noch am vorherigen arbeitet Rahmen. Wenn Sie solche Engpässe haben und sie nicht auf andere Weise beseitigen können, kann Pipelining der legitimste Grund sein, sich mit Subsystem-Threads zu beschäftigen.