Native AOT für kleine Kommandozeilenwerkzeuge

Native AOT für kleine Kommandozeilenwerkzeuge

- Matt

Ein kleines Werkzeug, das Logdateien durchsucht, braucht bei mir zwei Zehntelsekunden für die Arbeit und eine halbe für den Start der Laufzeit. Bei einem Aufruf ist das egal, in einer Schleife über zweihundert Dateien nicht mehr.

Native AOT übersetzt das Programm direkt in Maschinencode statt in IL. Eine Zeile in der Projektdatei:

<PropertyGroup>
  <PublishAot>true</PublishAot>
  <InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
dotnet publish -c Release -r win-x64

Heraus kommt eine einzelne EXE ohne installierte Laufzeit. Bei meinem Werkzeug: Startzeit von 480 auf 12 Millisekunden, Dateigröße 2,4 MB statt 150 KB plus Laufzeit.

Wo es scheitert

Alles, was zur Laufzeit Typen sucht oder erzeugt, funktioniert nicht mehr. Reflection über Namen, Activator.CreateInstance mit einem Typnamen aus einer Konfigurationsdatei, dynamische Proxies. Der Compiler warnt bei vielem davon, aber nicht bei allem.

Konkret betrifft das mehr Bibliotheken, als man denkt. Serialisierung ist der häufigste Fall, weshalb man den JSON-Quellgenerator braucht. Auch viele DI-Container, ORMs und Test-Frameworks fallen aus.

InvariantGlobalization ist der zweite Stolperstein: Es wirft die ICU-Bibliothek raus und spart damit ordentlich Platz, aber jede kulturabhängige Sortierung oder Datumsformatierung verhält sich danach anders. Für ein Werkzeug, das nur ASCII sieht, ist das in Ordnung. Für alles mit Nutzeroberfläche nicht.

Wofür ich es benutze

Kommandozeilenwerkzeuge, die oft und kurz laufen. Alles andere hat den Aufwand bei mir bisher nicht gerechtfertigt, weil man am Ende Bibliotheken austauscht, um eine Startzeit zu gewinnen, die niemand bemerkt.