El enfoque común para aprovechar múltiples núcleos es, francamente, simplemente equivocado. La separación de sus subsistemas en diferentes subprocesos dividirá parte del trabajo en varios núcleos, pero tiene algunos problemas importantes. Primero, es muy difícil trabajar con él. ¿Quién quiere jugar con las cerraduras y la sincronización y la comunicación y esas cosas cuando podrían simplemente escribir código de representación o física en su lugar? En segundo lugar, el enfoque en realidad no se amplía. En el mejor de los casos, esto le permitirá aprovechar quizás tres o cuatro núcleos, y eso si realmente sabe lo que está haciendo. Hay solo unos pocos subsistemas en un juego, y de esos hay incluso menos que ocupan grandes cantidades de tiempo de CPU. Hay un par de buenas alternativas que conozco.
Una es tener un subproceso principal junto con un subproceso de trabajo para cada CPU adicional. Independientemente del subsistema, el hilo principal delega tareas aisladas a los hilos de trabajo a través de algún tipo de cola (s); Estas tareas pueden crear otras tareas también. El único propósito de los subprocesos de trabajo es tomar cada tarea de la cola de una en una y realizarlas. Sin embargo, lo más importante es que tan pronto como un subproceso necesita el resultado de una tarea, si la tarea se completa, puede obtener el resultado, y si no, puede eliminar la tarea de la cola de manera segura y seguir adelante y realizar eso tarea en sí. Es decir, no todas las tareas terminarán siendo programadas en paralelo entre sí. Tener más tareas de las que se pueden ejecutar en paralelo es una buena opción.cosa en este caso; significa que es probable que se amplíe a medida que agrega más núcleos. Una desventaja de esto es que requiere mucho trabajo por adelantado para diseñar una cola decente y un bucle de trabajo a menos que tenga acceso a una biblioteca o tiempo de ejecución de idioma que ya lo proporciona. La parte más difícil es asegurarse de que sus tareas estén verdaderamente aisladas y seguras para los hilos, y asegurarse de que sus tareas estén en un punto medio feliz entre los granos gruesos y los granos finos.
Otra alternativa a los subprocesos del subsistema es paralelizar cada subsistema de forma aislada. Es decir, en lugar de ejecutar renderizado y física en sus propios hilos, escriba el subsistema de física para usar todos sus núcleos a la vez, escriba el subsistema de renderizado para usar todos sus núcleos a la vez, luego haga que los dos sistemas simplemente se ejecuten secuencialmente (o intercalados, dependiendo de otros aspectos de la arquitectura de tu juego). Por ejemplo, en el subsistema de física, podrías tomar todas las masas de puntos en el juego, dividirlas entre tus núcleos y luego hacer que todos los núcleos los actualicen a la vez. Cada núcleo puede trabajar en sus datos en ciclos cerrados con buena localidad. Este estilo de paralelismo de paso de bloqueo es similar a lo que hace una GPU. La parte más difícil aquí es asegurarse de que está dividiendo su trabajo en trozos de grano fino, de modo que se divida de manera uniformeen realidad da como resultado una cantidad igual de trabajo en todos los procesadores.
Sin embargo, a veces es más fácil, debido a la política, el código existente u otras circunstancias frustrantes, darle un hilo a cada subsistema. En ese caso, es mejor evitar hacer más subprocesos del sistema operativo que núcleos para cargas de trabajo pesadas de la CPU (si tiene un tiempo de ejecución con subprocesos livianos que simplemente equilibran sus núcleos, esto no es un gran problema). Además, evite la comunicación excesiva. Un buen truco es intentar canalizar; cada subsistema principal puede estar trabajando en un estado de juego diferente a la vez. La canalización reduce la cantidad de comunicación necesaria entre sus subsistemas, ya que no todos necesitan acceder a los mismos datos al mismo tiempo, y también puede anular algunos de los daños causados por los cuellos de botella. Por ejemplo, si su subsistema de física tiende a tardar mucho tiempo en completarse y su subsistema de representación termina siempre esperándolo, su velocidad de fotogramas absoluta podría ser mayor si ejecuta el subsistema de física para el siguiente fotograma mientras el subsistema de representación todavía funciona en el anterior cuadro. De hecho, si tiene tales cuellos de botella y no puede eliminarlos de otra manera, la canalización puede ser la razón más legítima para molestarse con los subprocesos del subsistema.