L'approccio comune per trarre vantaggio da più core è, francamente, semplicemente fuorviato. Separare i sottosistemi in thread diversi dividerà effettivamente parte del lavoro su più core, ma presenta alcuni problemi importanti. Innanzitutto, è molto difficile lavorare con. Chi vuole andare in giro con lucchetti, sincronizzazione, comunicazione e cose quando invece potrebbero semplicemente scrivere codice di rendering o fisica? In secondo luogo, l'approccio in realtà non si ingrandisce. Nella migliore delle ipotesi, questo ti consentirà di trarre vantaggio da forse tre o quattro core, e questo è se sai davvero cosa stai facendo. Ci sono così tanti sottosistemi in un gioco e di quelli ce ne sono ancora meno che occupano grossi pezzi di tempo della CPU. Ci sono un paio di buone alternative che conosco.
Uno è avere un thread principale insieme a un thread di lavoro per ogni CPU aggiuntiva. Indipendentemente dal sottosistema, il thread principale delega le attività isolate ai thread di lavoro tramite una sorta di coda (e); questi compiti possono anche creare altri compiti. L'unico scopo dei thread di lavoro è quello di prendere ogni attività dalla coda una alla volta ed eseguirle. La cosa più importante, tuttavia, è che non appena un thread necessita del risultato di un'attività, se l'attività viene completata può ottenere il risultato e, in caso contrario, può rimuovere in sicurezza l'attività dalla coda e andare avanti ed eseguirla compito stesso. Cioè, non tutte le attività finiranno per essere pianificate in parallelo tra loro. Avere più compiti di quanti possano essere eseguiti in parallelo è un benecosa in questo caso; significa che è probabile che si ridimensioni quando aggiungi più core. Un aspetto negativo di questo è che richiede molto lavoro in anticipo per progettare una coda e un ciclo di lavoro decenti a meno che tu non abbia accesso a una libreria o al runtime della lingua che già ti fornisce questo. La parte più difficile è assicurarsi che i tuoi compiti siano veramente isolati e sicuri per i thread, e assicurarti che i tuoi compiti siano in una felice via di mezzo tra grana grossa e grana fine.
Un'altra alternativa ai thread del sottosistema è quella di parallelizzare ciascun sottosistema in isolamento. Cioè, invece di eseguire il rendering e la fisica nei propri thread, scrivere il sottosistema di fisica per utilizzare tutti i core contemporaneamente, scrivere il sottosistema di rendering per utilizzare tutti i core contemporaneamente, quindi fare in modo che i due sistemi vengano eseguiti in sequenza (o interfogliati, a seconda di altri aspetti dell'architettura di gioco). Ad esempio, nel sottosistema di fisica potresti prendere tutte le masse di punti del gioco, dividerle tra i tuoi core e quindi far aggiornare tutti i core contemporaneamente. Ogni core può quindi lavorare sui tuoi dati in loop stretti con una buona località. Questo stile di parallelismo di blocco è simile a quello che fa una GPU. La parte più difficile qui è assicurarsi di dividere il lavoro in blocchi a grana fine in modo tale da dividerlo uniformementein realtà si traduce in una uguale quantità di lavoro su tutti i processori.
Tuttavia, a volte è più semplice, a causa della politica, del codice esistente o di altre circostanze frustranti, dare a ciascun sottosistema un filo. In tal caso, è meglio evitare di creare più thread del sistema operativo rispetto ai core per carichi di lavoro pesanti della CPU (se si dispone di un runtime con thread leggeri che si bilanciano tra i core, questo non è un grosso problema). Inoltre, evitare comunicazioni eccessive. Un bel trucco è provare il pipelining; ogni sottosistema principale può lavorare su uno stato di gioco diverso alla volta. Il pipelining riduce la quantità di comunicazione necessaria tra i sottosistemi poiché non hanno tutti bisogno di accedere agli stessi dati contemporaneamente e può anche annullare alcuni dei danni causati da strozzature. Per esempio, se il sottosistema di fisica tende a richiedere molto tempo per essere completato e il sottosistema di rendering finisce sempre in attesa, il frame rate assoluto potrebbe essere maggiore se si esegue il sottosistema di fisica per il fotogramma successivo mentre il sottosistema di rendering funziona ancora sul precedente telaio. In effetti, se si hanno tali colli di bottiglia e non è possibile rimuoverli in altro modo, il pipelining può essere il motivo più legittimo per preoccuparsi dei thread del sottosistema.