Ein Schlafmittel namens dotNet
« | 13 Mar 2021 | »Meine “Beziehung” zum dotNet Framework ist eine sehr sehr schwierige. Die Kernaufbau ist mir so verhasst, dass ich stets versuche an dotNet Sprachen nicht anzustreifen.
Gleichzeitig halte ich den Klassenaufbau des Frameworks selbst für ausgezeichnet durchdacht und vorbildhaft. Nicht grundlos habe ich viele Klassen- und Methodenkonventionen in die C++ Schicht des GATE Frameworks aufgenommen.
Neulich saß ich wieder vor einem meiner virtuellen
Windows Server, die auf
meinen stromsparenden Atom
Rechnern liefen.
Dann kam das monatliche dotNet Update und nach einer Stunde mühsamen
Updates (zusammen mit anderen nativen Windows Updates), lief dann über
2 Stunden die dotNet Runtime Optimierung und fraß die Systemressourcen
derart auf, dass das System unbenutzbar wurde.
Neben der CPU Auslastung waren vor allem die Festplattenzugriffe ein stark bremsenden Faktor.
Die Performance-Illusion
Die Idee eines Just-In-Time Compilers, (JIT) der erst zur Laufzeit Pseudocode in CPU-Code übersetzt, hat schon Java nie performant umsetzen können. Ich habe daher nie verstanden, wie man die Fehlentscheidung treffen konnte, die bestehende COM Struktur in Windows durch langsame JIT-dotNet Komponenten zu ersetzen.
Das hat man uns seit 2000 immer wieder als “beste Lösung” verkauft und erst seit ein paar Jahren rudert man mit dotNet Native und WinRT kräftig zurück.
Es stimmt zwar, dass manche Operationen mit modernen CPU-Instruktionen
wesentlich schneller laufen. Ein C oder C++ Programm aus dem Jahr 2003
hätte memcpy
in
einen Byte-zu-Byte Transfer übersetzt. Bereits 5 Jahre später war es aber
üblich, dass memcpy
auf das Alignment der Daten prüft und dann
SSE oder neuere
Vektor-Instruktionen einsetzt. Das geht tatsächlich dann 2 bis 4 mal schneller.
Man könnte also argumentieren, dass ein dotNet Programm von 2003 im Jahr 2008
ohne Zutun ob der neuen Instruktionen schneller ausgeführt wird, während das
C/C++ Kompilat keinen Performancegewinn ermöglicht.
Ja, das ist auch so. Man kann das teils schon bei der ZLIB
gut nachweisen.
(Habe das mal bei MSVC 2012
vs MSVC 2005 nachgemessen.)
Aber mal ehrlich! Zeitkritische Software wird stets weiterentwickelt und
spätestens alle paar Jahre neu ausgerollt. Im Normalfall benutzt also niemand
X-Jahre veraltete Software und hofft darauf, dass die Runtime-Umgebung diese
“schneller” macht.
Und zum Zeitpunkt der Veröffentlichung sind die nativen Routinen dank ihrer
hohen Optimierung stets schneller (oder im schlechtesten Fall gleich schnell)
wie “verwaltete” Programme.
Versionschaos
“Ein Framework” gab es seit v2.0 in dotNet leider nicht mehr. Mit jeder neuen Version kamen Features hinzu und weil die Entwicklungsumgebungen von Microsoft immer auf die neueste Inkarnation verweisen (und die Entwickler offenbar nichts hinterfragen), braucht fast jede Software ihr eigenes dotNet Paket.
Ganz besonders schlimm ist die Integration ins Betriebssystem. Ein dotNet
3.5 ist ein optionaler Teil von Windows 7
und kann nur per Windows Setup installiert werden. Ältere und neuere Versionen
müssen jedoch per MSI Setup
installiert werden, aber das macht die Administration und das Deployment
schwierig.
Und Windows 8 bis
Windows 10 stellen
wieder weitere 4.X Profile zur Verfügung, die auf älteren Systemen separat
und eben “anders” nachinstalliert werden müssen.
Dafür, dass dotNet letztlich nur ein “Wrapper” rund um das Betriebssystem ist,
und kein eigenes Subsystem, sind diese Inkompatibilitäten und
Installationshürden nicht gerade nachvollziehbar.
Und eben weil sich niemand mehr auskennt, welches Feature in welcher Version
mit welchem anderen funktioniert, entsteht der “Druck” zur neuesten Version
und einem ständigen Update mit immer wieder neuen Bugs.
DotNet Patches haben inzwischen die Größe der “üblichen” OS Patches erreicht
bzw. diese überschritten.
Und dass nach jedem Update sich das ganze System selbst neu durchkompiliert,
produziert unnötig Rechenlast, die die Last der eigentlichen Apps übersteigt.
Letztendlich erzeugen Millionen von Maschinen wegen dotNet jeden Tag den
gleichen Code.
… den Strom könnte man sich durchaus sparen!
Falschangaben beim Marketing
Anfangs hieß es:
C# und VB.NET sind rein statische Sprachen.
Und dann kam die Dynamic Language Runtime
und das Statement, dass man nun
die dynamische Typisierung, die es “intern immer schon gab”, auch in
allen Sprachen verfügbar gemacht hätte.
C# und VB.NET sind nach JIT Kompilierung “fast” gleich schnell wie C oder C++ Programme.
Das heißt dann quasi übersetzt: “Man kann es gar nicht schneller machen.”
… zumindest bis mit der nachfolgenden Initiative behauptet wurde:
dotNet Native ist um bis zu 60% schneller als die Implementierung des klassischen Frameworks.
Ein neuer Ahead-of-Time-Compiler erlaubt nun das Kompilieren ähnlich wie C oder C++ und deshalb ist dotNet jetzt fast oder genau so schnell.
Hmm … na, ich warte dann mal auf den nächsten Future-Prediction dotNet-Compiler, der wieder 50% schneller sein wird und damit WIEDER EINMAL gleichwertig mit C und C++ sein wird.
Fazit
Beim dotNet Marketing wird so viel Bullshit geplappert, dass es weh tut.
Die Beispiele, die die hohe Performance zeigen sollen, sind immer genau
auf die neueste Optimierung abgestimmt, stellen aber selten die
allgemeine Praxis nach. Das passiert leider auch bei quasi allen
Garbage-Collector-Vorführungen.
Wer Programme (egal mit welcher Technologie) testen will, sollte fertige
Applikationen auf Systemen mit geringen CPU und RAM Kapazitäten laufen
lassen.
Denn dort zeigt sich unmittelbar, dass kein Garbage-Collector “intelligent”
genug arbeitet und kein “verwaltetes” Framework performant arbeitet.
Und das wird noch deutlicher, wenn große Datenbanksysteme zeitkritisch
arbeiten sollen.
Aber eines muss ich leider eingestehen:
Schuld sind wir! Wir C und C++ Programmierer.
Denn obwohl native Sprachen die Chance bieten würden, wirklich effizient zu
arbeiten, sind eine Vielzahl der Entwickler, die mit diesen Sprachen arbeiten,
nicht fähig ordentliche Programme damit zu entwerfen.
Die Anzahl von Memory-Leaks,
Logikfehlern und falsch verstandenem Multithreading ist unerhört groß.
In allen Firmen, in denen ich bisher gearbeitet habe, zeigte sich das
Problem, dass niemand ausreichend auf Codequalität achtet, am wenigsten
leider das Management.
Und eben deshalb sucht “die Industrie” krampfhaft nach jemandem, der zumindest behauptet “Out-of-the-box” alles perfekt machen zu können.
dotNet, Java und jede Menge Python Scripts versuchen diese Lücken mit ebenso schlechten Implementierungen zu füllen und sind der Grund, warum wir in der IT seit langem keinen wirklichen Fortschritt mehr produzieren, sondern nur Wiederholungen der immer wieder gleichen Bugs und Workarounds.
… und dabei fing alles gut an, mit einem durchdachten Klassengerüst und
einer formal konsistenten Infrastruktur.
Schade, dass unter dieser schönen Hülle und fauliger Kern steckt.
Wie auch immer … ich versuche nach bestem Wissen und Gewissen aus diesen Fehlern zu lernen.