[/fusion_text]

JOB SYSTEM

Breve descripción

Vamos a empezar ahora con palabras un poco mayores. Este sistema nos permite trabajar con multithreading de una manera fácil mientras a su vez podemos seguir utilizando cosas de Unity (que originalmente no podían usarse en multithreading). En términos generales lo que nos permite es realizar tareas en multithreading ahorrándonos la engorrosa tarea de crear, gestionar y eliminar los threads creados. Básicamente le decimos: “quiero procesar esto en multithreading” y el sistema se encarga de crear los threads (si es necesario crearlos), de dividir las tareas en los distintos threads y de, cuando sea necesario, eliminar dichos threads. De más está decir que, al formar parte del grupo de tecnologías de DOTS, también es compatible con todo lo que vimos en un principio de Entity Component System. Y más adelante van a notar también que de hecho ese sistema ya utiliza estos jobs actualmente, sólo que nunca se los dije. Je.

Por qué, o para qué, usar Job System fuera de ECS?

Veamos a ECS como una nueva, y mejorada, forma de estructurar determinado tipo de cosas. Hago énfasis en eso porque en realidad usamos ECS para algunas cosas que suelen ser muy costosas, y no para otras como mostrar un texto en pantalla. No es que vamos a hacer TODO nuestro juego utilizando este sistema. Pasa un poco lo mismo con el Job System. No es que necesitamos usarlo para todo, pero podemos utilizarlo para hacer pequeñas tareas aisladas, como procesar muchas entidades para obtener una posición o velocidad promedio, o detectar algo específico dentro de un grupo grande de objetos. Pero particularmente para procesar MUCHA información de golpe.

 

Cuándo usar ECS y cuándo usar Job System?

Por supuesto está demás aclarar que no necesariamente hay que usarlos por separados, pero YO en mi caso particular, y en este momento de conocimiento los usaría en casos puntuales. Hago la aclaración de YO porque es una tecnología en proceso, es una forma diferente de estructurar las cosas dentro del juego y también es algo que está en constante mejora, por lo cual aclaro que es simplemente mi opinión. Dicho lo anterior, yo usaría ECS para la gestión de sistemas que van a correr durante TODO nuestro juego o al menos la mayor parte del tiempo, y más en momentos core, y usaría específicamente Job System para tareas más puntuales como Path Finding o algún procesamiento de datos muy grande, como los relacionados a la inteligencia artificial de los personajes o redes neuronales (por ejemplo, atacar al personaje más débil, o al más cercano, etc).

 

Empezando a usar Job System

Vamos a hacer una pequeña prueba. Pero esta vez vamos a desligarnos un poco de ECS para que vean cómo funciona asilado. Luego vamos a mostrar cómo hacer que funcionen juntos. Vamos a hacer un MonoBehaviour tradicional, para crear muchas cajas y moverlas con un Job que vamos a programar para ejemplificar su uso. Nuestro Job va a ser un struct y va a tener la siguiente forma inicial.

Copy to Clipboard

 

Cosas que pueden ser remarcables del código anterior:

  • IJobParallelForTransform: Esta interfaz es la clave para nuestros jobs con el formato que vamos a usar. Hay varias interfaces para jobs, pero esta en particular representa una especie de ForEach con la utilización de Transforms.
  • TransformAccess: Es es una estructura que nos da acceso a la posición, rotación y escala de un transform. Está hecha para trabajar de forma óptima con Job System. Más info en la documentación de Unity.
  • Execute: Es el método al que se va a llamar cuando este Job forme parte de una iteración en multithreading. El mismo sistema nos va a pasar el índice dentro del array que se está recorriendo y el TransformAccess correspondiente.

Vamos a continuación escribir el código necesario para que el Job haga lo que querémos lograr (llevar a nuestras cajas al centro). Para ello vamos a agregar algunas líneas a ese Job que creamos.

 

Copy to Clipboard

Lo que hicimos fue:

  • deltaTime: Al crear nuestro Job vamos a acceder al valor actual del deltaTime y pasarselo. Esto es por la misma premisa que tiene Unity con el tema de multithreading: Sólo podemos acceder a las cosas de UnityEngine desde el main thread. Este tema de los Jobs nos da un acceso a algunas herramientas, aunque en realidad lo que hace es darnos algunas herramientas para poder llevar a cabo esa tarea.
  • La línea que agregamos en el Execute es básicamente para mover el objeto hacia el punto cero.

Con esto nuestro Job estaría listo para ser ejecutado. Imagino que instanciar multiples cajas en la escena debe ser tarea fácil si están leyendo este post, pero dejo el código debajo por si las dudas.

Copy to Clipboard

 

Gran parte, imagino, no debe ser nuevo para ustedes. Pero seguramente hay partes puntuales que no estan del todo claras, así que vamos a explicar un poco.

  • TransformAccessArray: Recuerdan todo lo anterior que explicamos acerca de TransformAccess? Bueno… Esto representa un array de eso básicamente. Lo que hacemos en este código es básicamente agregar cada uno de los transform de las instancias que vamos generando de nuestras cajas.
  • MoveToCenterJob: Esta variable no tiene mucha explicación. Lo único que va a hacer es guardar nuestra instancia actual del job que vamos a crear.
  • JobHandle: La variable de este tipo lo que va a hacer es guardar una referencia al proceso que se encarga de procesar nuestro job. Mediante esta variable lo vamos a poder completar.
  • Schedule: Noten que luego de crear nuestro Job en la última línea llamamos al método Schedule para iniciar nuestro Job y guardamos la resultante en la variable jobHandle. Con esto lo que estamos haciendo es inicializar el job para que Unity haga todo lo que tenga que hacer para que se ejecute en multithreading. Y luego, en el método LateUpdate, que se ejecuta después de todos los Update, lo que hacemos es completar nuestro job. Lo que hace esto es asegurar que el job se completó antes del siguiente Update.
  • Dispose: Esto es para asegurarnos de liberar los recursos correctamente. En muchos casos nos vamos a encontrar con que tenemos que liberar los recursos a mano. Es una manera más de gestionar nosotros los recursos.

Si quieren, para comparar, creen un algoritmo para mover las cajas con un Update tradicional, poniendolas todas en un array y recorriendo frame a frame dicho array.

 

Copy to Clipboard

 

Hay algo más que podemos hacer para que estos Jobs sean aún más óptimos…