Ich bin oft versucht, das Spiel zu brechen, an dem ich arbeite, um eine auf parallelen Aufgaben basierende Architektur auszuprobieren, aber das scheint keine große Voraussetzung für mein Projekt zu sein, deshalb vermeide ich dies im Moment. Ich habe vor, es zuerst in einem Spielzeugprojekt zu versuchen, um "mit dem Konzept zu spielen".
Was ich jetzt frage, ist, dass viele (Nicht-AAA-) Spiele keine wirklich sehr hohe Leistung erfordern. Es scheint, dass es sich nicht lohnt, eine aufgabenbasierte Engine zu verwenden, bis ... in welchen Fällen?
Im Moment vermute ich nur, dass es notwendig ist, wenn Sie wirklich die maximale Leistung der (Multi-Core-) Hardware nutzen müssen. Gibt es andere Fälle, in denen es eine gute Idee ist, eine aufgabenbasierte Engine zu verwenden? Oder ist es für neue Projekte immer gut, mit einer aufgabenbasierten Engine zu beginnen?
quelle
Wenn Ihr Spiel remote hardwareintensiv sein soll, benötigen Sie Threads, um mit der gesamten modernen Hardware fertig zu werden. Zukünftige CPUs, die in den nächsten ein oder zwei Jahren herauskommen, beginnen, mindestens 4 Kerne und bis zu 16 Kerne für Enthusiasten- / Leistungsmärkte zu verwenden. Wenn Sie überhaupt Multithreading ausführen, sollten Sie auf jeden Fall eine aufgabenorientierte Architektur erstellen, da jedes andere Threading-Modell für zukunftsweisende Spiel-Engines von Natur aus fehlerhaft ist.
Denken Sie jetzt daran, dass mit "Aufgaben" "Jobs" und nicht "separate Threads für verschiedene Engine-Subsysteme" gemeint sind. Sie möchten absolut nichts wie einen Grafik-Thread, einen Physik-Thread, einen KI-Thread usw. tun. Das skaliert nicht über eine winzige Handvoll Kerne hinaus und bringt Ihnen ohnehin keine echte Parallelität. Die Physik sollte nicht mehr als ein Update pro KI-Update ausführen (Sie möchten, dass Ihre KI auf Physikereignisse reagieren kann), und Grafiken müssen fast nichts Neues gerendert werden, wenn die Physik nicht ausgeführt wurde. Daher wird jedes Subsystem natürlich in einer Sequenz ausgeführt Auftrag. Du ziehst nicht
Was Sie tun möchten, ist dies. Erstellen Sie eine Garnrolle. Führen Sie Ihre Spielschleife mit der klassischen Folge von Subsystem-Updates aus. Trennen Sie jedoch für jedes Subsystem die Arbeitslast in verschiedene trennbare Stapel und verteilen Sie diese auf den Thread-Pool. Warten Sie, bis alle Jobs abgeschlossen sind, bevor Sie den nächsten Status der Spielaktualisierungsschleife ausführen. Einige Subsysteme können mehrere Unterstufen haben. Beispielsweise können Grafiken eine Reihe von Jobs zum Ausmerzen und dann eine zweite Reihe von Jobs zum Erstellen der Renderwarteschlange ausgeben. Dieser Ansatz vermeidet das Synchronisationsproblem des ersten Ansatzes, skaliert auf eine viel größere Anzahl von Kernen und ist offen gesagt einfacher zu codieren, zu debuggen und zu warten.
quelle
Beim Multithreading gibt es zwei Verwendungszwecke: Zum einen zur Verbesserung der Programmleistung und zum anderen zum Ausführen des Programms, wenn ein großer Prozess ausgeführt wird. Wenn Sie beispielsweise versuchen, einige Daten zu laden, ist es störend, wenn Ihr Programm auflegt. Sie können daher einen anderen Thread zum Laden verwenden und den Haupt-Thread frei halten, um die Hauptschleife fortzusetzen. Die Verbesserung der Leistung mithilfe von Threads ist dagegen sehr schwierig. da man normalerweise alles in einem linearen prozess macht und das ist etwas im gegensatz zur parallelverarbeitung. und Sie müssen immer Ihren Hauptthread für grafische Geräteaktualisierungen verwenden, was es noch schwieriger macht, Aufgaben zwischen Threads aufzuteilen.
quelle