Unity y .NET, ¿qué sigue?

Recientemente hemos puesto en marcha una iniciativa plurianual para ayudarte a escribir código más eficiente y rápido, y para ofrecerte estabilidad y compatibilidad a largo plazo. Sigue leyendo para descubrir qué estamos haciendo para actualizar la infraestructura tecnológica fundamental que sustenta tus scripts.
El ecosistema .NET está evolucionando dinámicamente de diversas maneras beneficiosas, y queremos ofrecerles esas mejoras lo antes posible. Nuestro grupo técnico interno de .NET trabaja en la mejora continua de nuestra integración con .NET, incluyendo las nuevas características de C# y .NET Standard 2.1 . Pero recientemente hemos acelerado el ritmo para mejorar tu experiencia como desarrollador en todos los aspectos, basándonos en tus comentarios.
Esta entrada de blog presenta los temas en los que estamos trabajando. También hemos tratado este tema en la Cumbre de Desarrolladores de Unity en la GDC 2022. Puedes ver la sesión completa aquí .
La historia comienza hace 17 años, cuando nuestro director de tecnología empezó a utilizar el entorno de ejecución Mono .NET con C#. Unity se decantó por C# debido a su simplicidad, combinada con un compilador JIT (justo a tiempo) que traduce el código C# a código nativo relativamente eficiente. Las partes restantes y mucho más extensas del motor Unity se han desarrollado utilizando C++ para proporcionar un rendimiento equilibrado y controlado.
Durante muchos años, Unity había estado funcionando con una bifurcación específica del entorno de ejecución Mono .NET y el lenguaje C# (2.0). Durante ese tiempo, hemos añadido compatibilidad con plataformas adicionales. También hemos desarrollado nuestro propio compilador y entorno de ejecución, IL2CPP, para que puedas desarrollar aplicaciones para iOS y algunas plataformas de consola.
Mientras tanto, el ecosistema general de Microsoft .NET ha evolucionado, con nuevas licencias y compatibilidad con plataformas que no son Windows. Esta evolución nos ha permitido actualizar el entorno de ejecución Unity .NET Mono en 2018 e incorporar versiones más modernas del lenguaje C# (7.0+). Ese mismo año, también lanzamos la primera versión del compilador Burst , pionero en la generación de código nativo rápido para un subconjunto del lenguaje C#. Este avance permitió a Unity imaginar un mundo donde podríamos extender el uso de C# en otros segmentos críticos del motor sin tener que desarrollar esas partes en C++, lo que llevó al desarrollo del entorno de ejecución DOTS .
Unity 2020 LTS y Unity 2021 LTS incorporaron versiones más recientes del lenguaje C# y nuevas API de .NET. Paralelamente, hemos visto mejoras de rendimiento extraordinarias en el ecosistema .NET, así como un entorno de desarrollo más amigable con la introducción de csproj al estilo SDK y el floreciente ecosistema NuGet.
Como resultado de esta larga evolución, la plataforma Unity incluye una base de código C++ muy extensa que interactúa directamente con objetos .NET utilizando supuestos específicos heredados del entorno de ejecución Mono .NET. Estas opciones ya no son válidas ni eficientes para el entorno de ejecución .NET (Core).
Además, existe un complejo proceso de compilación personalizado vinculado al editor de Unity que no depende de MSBuild y, por lo tanto, no puede beneficiarse fácilmente de todas las funciones estándar.
También hemos estado hablando con muchos de ustedes durante los últimos años, tanto en entrevistas como en el foro de Unity , para ver qué podríamos mejorar para facilitarles un mayor éxito. Según tenemos entendido, usted desea utilizar la última versión del lenguaje C#, la tecnología de tiempo de ejecución .NET y código C# de terceros procedente de NuGet. En lo que respecta al uso de la plataforma Unity , nos comentaste que querías sacar el máximo partido al hardware de destino con herramientas de prueba, depuración y análisis de rendimiento de C# de alta calidad, y una buena integración entre la API estándar de .NET y la API de Unity . Como programador de C# en Unity , usted desea herramientas que se Unity a la perfección con el resto de sus herramientas y que permitan una iteración rápida para que pueda lograr el mejor rendimiento en tiempo de ejecución.
Llegar allí nos llevará varios años. Les mantendremos informados mediante actualizaciones frecuentes en el blog y el foro sobre los desafíos técnicos que encontremos en el camino.
Nuestro primer paso en esta iniciativa fue reunir a todas las personas internas apasionadas por C# y .NET en Unity para formar un Grupo Técnico de C#/.NET que impulsara este esfuerzo.
Queremos construir sobre el ecosistema .NET en lugar de desarrollar soluciones a medida. Para que puedas aprovechar las mejoras de rendimiento y productividad que ofrecen el SDK/Runtime de .NET más reciente y MSBuild, queremos migrar del entorno de ejecución Mono .NET a CoreCLR, el entorno de ejecución moderno de .NET (Core).
Esta iniciativa también te ofrece innovaciones que van más allá del universo .NET existente, con el objetivo de lograr ciclos de iteración .NET más rápidos en tus scripts de C#. Trabajaremos para lograr la convergencia de las soluciones JIT y AOT (compilación anticipada) – IL2CPP y Burst – para ofrecer el mejor equilibrio entre la eficiencia en tiempo de compilación y la calidad de la generación de código.
Externamente, estamos colaborando con socios del sector como Microsoft y JetBrains para garantizar que los creadores de Unity utilicen la tecnología .NET más reciente. También estamos incrementando nuestra participación en comunidades de código abierto. Vamos a dividir este proyecto en varios pasos. Veamos qué viene después.
Este año, los equipos planean trabajar en las siguientes pistas.

El tiempo de iteración sigue siendo nuestra máxima prioridad, ya que sabemos que usted quiere sacar el máximo provecho de su tiempo. Aquí tenéis algunos ejemplos de lo que estamos haciendo para mejorar esto.
- Como parte del proceso de compilación, estamos mejorando el tiempo que dedica el procesamiento posterior de IL, que es el responsable de modificar los ensamblados .NET compilados después de que se haya compilado su código C#. Ahora estamos utilizando un proceso persistente para ejecutar el posprocesamiento de IL después de la fase de compilación, lo que puede ahorrar unos cientos de milisegundos.
- Dado que el compilador Burst se utiliza con mayor frecuencia, estamos mejorando la precisión en la detección de cambios en el código mediante un algoritmo de hash transitivo. Esto nos permite identificar qué código Burstable necesitamos compilar más rápidamente. Estamos trabajando para que el compilador Burst se ejecute fuera del proceso principal, de modo que pueda compilar su código más rápido gracias a que se ejecutará en un ejecutable .NET 6.0 independiente.
- También estamos mejorando la recarga del dominio optimizando los datos de reflexión que se generan internamente cada vez que se utiliza TypeCache .
- Vamos a añadir pruebas y validación para realizar un mejor seguimiento de la regresión del tiempo de iteración para los paquetes y las plantillas de proyecto.
Para la migración a MSBuild , el primer paso es desacoplar nuestra canalización de compilación del Editor de Unity y trasladarla a un proceso separado. Se trata de una operación compleja, ya que existen años de código heredado con miles de líneas de código C++ y C# que debemos desenredar para lograrlo, manteniendo al mismo tiempo la compatibilidad con versiones anteriores. Desde tu punto de vista, no verás cambios, pero allanará el camino hacia MSBuild y simplificará el mantenimiento.
También vamos a mejorar la experiencia de depuración del IDE de C# con Burst introduciendo un modo que cambiará automáticamente el depurador a la depuración administrada cuando se establezca un punto de interrupción en una ruta de código que se ejecute con Burst. Esto significa que no tendrá que eliminar manualmente el atributo [BurstCompile] en la ruta de código que se está depurando.
El trabajo que supone la migración al entorno de ejecución .NET CoreCLR ya ha comenzado, y se trata de un proceso muy complejo. Para poder llevar a cabo esta migración con éxito, nos gustaría abordar el problema gradualmente y asegurarnos de que podemos lanzar las diferentes partes de forma que se mantenga la estabilidad de los proyectos de Unity existentes.
Por lo tanto, planeamos llevar a cabo esta migración en varias fases:
- En primer lugar, ofreceremos compatibilidad con .NET CoreCLR para reproductores independientes en plataformas de escritorio . Podrás seleccionar este entorno de ejecución en la configuración de tu reproductor, junto con los backends Mono e IL2CPP ya existentes. Esta primera fase debería ayudarnos a migrar la parte central del motor Unity (que es mucho más pequeña que la parte del editor) y, con suerte, resolverá una buena parte de los desafíos técnicos que implica esta migración. Seguirás accediendo al entorno de ejecución de .NET a través de la API.NET Standard 2.1, y nuestro objetivo es lanzar este nuevo entorno de ejecución durante 2023.
- En segundo lugar, vamos a portar el editor de Unity a .NET CoreCLR y, al mismo tiempo, eliminaremos la compatibilidad con el entorno de ejecución .NET Mono . Esta segunda fase pondrá a prueba cómo vamos a recargar tus scripts en el Editor sin usar AppDomains y completar la transición a .NET CoreCLR. También implicará actualizar IL2CPP para que sea compatible con las bibliotecas de clases base del repositorio dotnet/runtime. Finalmente tendrás acceso a la API completa de .NET 7.x u 8.0. Esperamos lanzar este nuevo editor durante 2024.
La compatibilidad con .NET Standard 2.1 en Unity 2021 LTS nos permite comenzar a modernizar el entorno de ejecución de Unity de diversas maneras. Actualmente estamos trabajando en dos mejoras.
Mejorando el modelo de programación async/await . Async/await es un enfoque de programación fundamental para escribir código de juego que debe esperar a que una operación asíncrona se complete sin bloquear el bucle principal del motor.
En 2011, antes de que async/await se generalizara en .NET, Unity introdujo operaciones asíncronas con corrutinas basadas en iteradores, pero este enfoque es incompatible con async/await y puede ser menos eficiente. Mientras tanto, .NET Standard 2.1 ha mejorado la compatibilidad con async/await en C# y .NET con la introducción de un manejo más eficiente de las operaciones async/await a través de ValueTask y permitiendo su propio sistema similar a una tarea a través de AsyncMethodBuilder.
Ahora podemos aprovechar estas mejoras, por lo que estamos trabajando para habilitar el uso de async/await con las operaciones asíncronas existentes en Unity (como esperar al siguiente fotograma o esperar a que finalice una UnityWebRequest). Como primer paso, estamos mejorando la compatibilidad para cancelar tareas asíncronas pendientes cuando se destruye un MonoBehavior o cuando se sale del modo de reproducción mediante el uso de tokens de cancelación . También hemos estado trabajando estrechamente con nuestros principales colaboradores de la comunidad, como el autor de UniTask , para garantizar que puedan aprovechar estas nuevas funcionalidades.
Reducción de las asignaciones y copias de memoria mediante el uso de Span. Dado que Unity es un motor de C++ con una capa de scripting en C#, se intercambia una gran cantidad de datos entre ambos. Esto puede resultar ineficiente, ya que a menudo requiere copiar datos de un lado a otro o asignar nuevos objetos gestionados.
Span se introdujo en C# 7.2 para mejorar este tipo de escenarios y está disponible de forma predeterminada en .NET Standard 2.1. En los últimos años, es posible que hayas oído o leído sobre muchas mejoras de rendimiento significativas realizadas en .NET Runtime gracias a Span (consulta los detalles de las mejoras en .NET Core 2.1 , .NET Core 3.0 , .NET 6 , .NET 6 ). Queremos aprovechar su uso en Unity, ya que esto ayudará a reducir las asignaciones de memoria y, en consecuencia, las pausas de la recolección de basura, al tiempo que mejora el rendimiento general de muchas API.
Esperamos que todos ustedes estén tan entusiasmados como nosotros con estos cambios y nuevas funciones.
Háganos saber su opinión sobre nuestros planes en el foro . También actualizaremos periódicamente la sección de ingeniería de la hoja de ruta de la plataforma Unity , y allí podrás compartir tus solicitudes de nuevas funciones y sugerencias de priorización.
Nota del editor: Este artículo se actualizó por última vez en febrero de 2023.
