L’approche commune pour tirer parti des multiples cœurs est, franchement, tout simplement erronée. Si vous séparez vos sous-systèmes en différents threads, vous aurez en fait une partie du travail dans plusieurs cœurs, mais cela pose des problèmes majeurs. Premièrement, il est très difficile de travailler avec. Qui veut s'amuser avec des verrous, la synchronisation, la communication et d'autres choses alors qu'il pourrait simplement écrire du code de rendu ou de physique à la place? Deuxièmement, l'approche n'augmente pas réellement. Au mieux, cela vous permettra de tirer avantage de trois ou quatre cœurs, et ce, si vous savez vraiment ce que vous faites. Un jeu ne contient qu'un nombre limité de sous-systèmes, et il y en a même moins qui prennent beaucoup de temps CPU. Il y a quelques bonnes alternatives que je connais.
L'une consiste à avoir un thread principal avec un thread de travail pour chaque CPU supplémentaire. Quel que soit le sous-système, le thread principal délègue des tâches isolées aux threads de travail via une sorte de file d'attente; ces tâches peuvent elles-mêmes créer encore d'autres tâches. Les threads de travail ont pour seul objectif de saisir et d'exécuter les tâches de la file d'attente, une par une. La chose la plus importante, cependant, est que dès qu'un thread a besoin du résultat d'une tâche, si la tâche est terminée, il peut obtenir le résultat et si ce n'est pas le cas, il peut supprimer la tâche en toute sécurité de la file d'attente et continuer tâche elle-même. En d'autres termes, toutes les tâches ne seront pas planifiées en parallèle les unes avec les autres. Avoir plus de tâches que ce qui peut être exécuté en parallèle est un bonchose dans ce cas; cela signifie qu'il est susceptible d'évoluer à mesure que vous ajoutez plus de cœurs. Un inconvénient est qu’il faut beaucoup de travail en amont pour concevoir une file d’attente et une boucle de travail correctes, sauf si vous avez accès à une bibliothèque ou à un environnement d’exécution linguistique qui vous en fournit déjà un. La partie la plus difficile consiste à vous assurer que vos tâches sont vraiment isolées et sécurisées, et à vous assurer que vos tâches se situent dans un juste milieu entre le grain grossier et le grain fin.
Une autre alternative aux threads de sous-système consiste à paralléliser chaque sous-système de manière isolée. Autrement dit, au lieu d'exécuter le rendu et la physique dans leurs propres threads, écrivez le sous-système physique pour utiliser tous vos cœurs en même temps, écrivez le sous-système de rendu pour utiliser tous vos cœurs en même temps, puis laissez les deux systèmes s'exécuter simplement de manière séquentielle (ou entrelacée). en fonction d'autres aspects de votre architecture de jeu). Par exemple, dans le sous-système physique, vous pouvez regrouper toutes les masses de points du jeu, les répartir entre vos cœurs, puis les mettre à jour simultanément. Chaque noyau peut alors travailler sur vos données en boucles serrées avec une bonne localisation. Ce style de parallélisme à verrouillage est similaire à ce que fait un GPU. La partie la plus difficile ici consiste à vous assurer que vous divisez votre travail en morceaux fins comme ceux-ci.se traduit par une charge de travail égale pour tous les processeurs.
Cependant, il est parfois plus facile, en raison de la politique, du code existant ou d’autres circonstances frustrantes, de donner un fil à chaque sous-système. Dans ce cas, il est préférable d'éviter de créer plus de threads de système d'exploitation que de cœurs pour les charges de travail lourdes du processeur (si vous avez un environnement d'exécution avec des threads légers qui équilibrent simplement vos cores, le problème n'est pas aussi grave). Évitez également les communications excessives. Une bonne astuce consiste à essayer de pipeliner; chaque sous-système majeur peut travailler sur un état de jeu différent à la fois. Le traitement en pipeline réduit la quantité de communication nécessaire entre vos sous-systèmes, car ils n'ont pas tous besoin d'accéder aux mêmes données en même temps et peut également annuler certains des dommages causés par les goulots d'étranglement. Par exemple, si votre sous-système physique a tendance à prendre beaucoup de temps et que votre sous-système de rendu finit toujours par l'attendre, votre fréquence d'images absolue pourrait être supérieure si vous exécutez le sous-système physique pour la trame suivante pendant que le sous-système de rendu fonctionne toujours sur le précédent. Cadre. En fait, si vous avez de tels goulots d'étranglement et que vous ne pouvez pas les supprimer, le traitement en pipeline peut être le motif le plus légitime de s'inquiéter des threads de sous-système.