Un código mas eficiente en .NET gracias a Native AOT

Durante las últimas versiones de .NET el equipo de Microsoft se ha estado centrado mucho en rendimiento, una de las funcionalidades que nos han dado es con Native AOT Compilation, aquí vamos a ver como funciona los beneficios y algún caso de uso.

 

 

1 - Qué es Native AOT en .NET?

Como todos sabemos, .NET, cuando compilas en tu máquina, lo que hace es compilar en lo que se denomina IL o Intermediate Language. Luego es el Runtime de .NET (CLR) es el que compila en código máquina a través del compilador Just in time (JIT).

 

 

Así es como .NET ha funcionado durante años, pero ya en la netconf de 2022 presentaron un avance de lo que hoy en día conocemos como Native AOT.

Lo que Native AOT nos permite hacer es compilar nuestro código C# en código nativo en la propia máquina donde estamos compilando, no necesitamos el paso intermedio de compilar a IL.

En el caso de windows, por ejemplo, nos da un .exe;

    • Nota: Técnicamente compila a IL y de IL a máquina, pero se hace todo en el mismo compilado, así que es transparente para el usuario.

 

 

2 - Ventajas y desventajas de Native AOT en .NET

Como todo en programación, tenemos ventajas y desventajas. Antes de continuar, quiero hacer hincapié en que en el cliente donde estoy, por ahora no se utiliza native AOT, pero hay planes de empezar a implementarlo durante 2024; esta información está principalmente sacada de conferencias y obviamente de algún test que he ejecutado yo mismo. 

 

El punto principal de Native AOT es el rendimiento, al compilar directamente a máquina no tenemos que perder tiempo en compilar de IL a máquina durante el tiempo de ejecución, así  que es más rápido, especialmente en primeras ejecuciones

Para el que no lo sepa el JIT compiler se ejecuta la primera vez que un método es invocado, luego ya se queda compilado.

Piensa en una azure function/lambda, ahora que están tan de moda, mucho tiempo se pierde en el startup, Native AOT reduce este tiempo de inicialización drásticamente, y por tanto el coste económico.

 

 

Por supuesto al compilar en código máquina y para una máquina específica significa que el mismo código compilado no va a funcionar en múltiples sistemas. Por ejemplo, si tu máquina es windows, solo puedes compilar para windows, si quieres compilar para linux necesitas compilar en una máquina linux. Sin utilizar Native AOT, tu compilas en tu máquina y el .dll resultante se puede ejecutar en cualquier sitio.

 

Pero, como cabe esperar, tenemos una razón por la que esto funciona de esta manera. He dicho antes que cuando compilamos en windows nos da un exe, un exe que por supuesto se puede ejecutar, eso quiere decir que todo lo que tu app necesita para funcionar está dentro de ese ejecutable, la máquina donde estas ejecutando el código no necesita tener instalado el runtime de .NET o ninguna dependencia. Lo mismo sucede en el caso de linux, o lo mismo sucedería en una arquitectura de 32 bits y una de 64, aunque ambos sean windows.

 

A su vez esta acción nos genera otro efecto secundario y es que tanto el tiempo de compilación, como el tamaño de la aplicación es mucho mayor cuando utilizamos native AOT que cuando compilamos por defecto.

 

Finalmente, aunque este punto es más temporal, no podemos hacer todas las aplicaciones AOT. Para que tu aplicación sea compatible con Native AOT, todas las dependencias que estás utilizando deben ser compatibles con Native AOT. Por norma general muchas lo son, pero por ejemplo, Entity framework core no está soportado, webAPI no está soportado, cuando usas reflection algunas cosas sí están soportadas y otras no, así que por ahora no podemos decir que sea una solución 100% funcional. 

 

 

3 - Ejemplo de Native AOT en .NET

Ahora vamos a ver un ejemplo y comparar una aplicación “normal” y una con Native AOT, la app en si va a ser la misma, la minimal API que nos da por defecto Microsoft, porque minimal API si esta soportado por native AOT. 

Así que veamos.

 

Primero de todo debemos ir al visual studio installer e instalar los paquetes de Desktop development con C++; técnicamente los podemos instalar a mano, pero aquí nos viene todo en un solo click.

c++ desktop development

Por cierto estas librerías ocupan más de 6gb, así que puede tardar un poco.

 

Una vez tenemos esto, creamos un proyecto, podemos buscar por AOT  o directamente:

proyecto aot

Hay varias diferencias con lo que es una minimal api normal, aquí tienes un post de microsoft donde te indica cuales son.

Pero yo destaco principalmente dos, cuando estamos creando nuestro builder  estamos creando un SlimBuilder en vez de un builder, esto es porque contiene lo minimisimo que vas a necesitar para correr la aplicación.

var builder = WebApplication.CreateSlimBuilder(args);

Y el otro detalle principal es que dentro de lo que viene siendo el .csproj del proyecto hay una propiedad llamada PublishAot asignada a true.

<PublishAot>true</PublishAot>

Para hacerlo lo más realista posible, el código es lo más similar posible, eso quiere decir que ambos tienen los mismos endpoints con la misma funcionalidad, por ejemplo a la web api le he quitado swagger.

 

3.1 - Diferencia de peso en Native AOT

En ambos casos podemos hacer dotnet publish, de hecho en el el caso de Native AOT es obligatorio. Para tener los resultados más precisos, lo hacemos en ambos.

 

Este es el resultado de ambas versiones: 

diferencia de peso aot y normal

Como vemos uno es un .dll (y un ejecutable que lo ejecuta) y el otro es puramente un ejecutable, sin dll alrededor, y lo que es más chocante, mucho más pesado. 

Y obviamente en una imagen no se ve, pero cuando publique el vídeo veréis que tarda bastante más en compilar el native AOT. 

 

La versión de native aot está ubicado en \bin\Release\net8.0\win-x64\publish

La versión por defecto: DefaultExample\bin\Release\net8.0\publish

Como puedes ver, la versión de native aot incluye el win-x64 de la máquina y arquitectura que está siendo utilizada para su compilación;

 

 

3.2 - Diferencia de rendimiento en Native AOT

 

Para este ejemplo no sabía si simplemente utilizar el ejemplo o hacer algo adicional, al final me he decantado para darle un poco más de realismo a hacer una APP que consulta en la base de datos, simplemente valores planos, nada complejo, porque es verdad que EF no está soportado, pero Dapper si lo está, aunque no completamente.

 

Además les he metido a ambas un middleware que calcula el tiempo de ejecución.

Ambas aplicaciones son iguales, la única diferencia es el compilado, y que la versión AOT necesita de Dapper.AOT, y aquí podemos unas pocas de ejecuciones de ejemplo.

native aot vs normal

Este ejemplo es muy sencillo, por lo que hablamos de muy pocos microsegundos de diferencia, pero ya es algo sustancial si tienes miles de llamadas por minuto.

A lo largo del año o de las versiones de .NET estoy seguro de que tendremos mejoras de las librerías de terceros que utilizamos para que puedan ser compiladas con NativeAOT. 

Por ahora es un muy buen comienzo.


Uso del bloqueador de anuncios adblock

Hola!

Primero de todo bienvenido a la web de NetMentor donde podrás aprender programación en C# y .NET desde un nivel de principiante hasta más avanzado.


Yo entiendo que utilices un bloqueador de anuncios como AdBlock, Ublock o el propio navegador Brave. Pero te tengo que pedir por favor que desactives el bloqueador para esta web.


Intento personalmente no poner mucha publicidad, la justa para pagar el servidor y por supuesto que no sea intrusiva; Si pese a ello piensas que es intrusiva siempre me puedes escribir por privado o por Twitter a @NetMentorTW.


Si ya lo has desactivado, por favor recarga la página.


Un saludo y muchas gracias por tu colaboración

© copyright 2024 NetMentor | Todos los derechos reservados | RSS Feed

Buy me a coffee Invitame a un café