Aus einem weitgehend irrelevanten Grund habe ich Delphi 7 in so langer Zeit erneut installiert. Ich muss sagen, ich war total überwältigt - in gewisser Weise schon länger nicht mehr. So kann ich mich überhaupt nicht erinnern. Die Installation dauerte ca. 30 Sekunden. Der Start dauerte 2 Sekunden und war sofort einsatzbereit. Ich kann "Ausführen" in der Sekunde nach dem Start drücken, und weniger als eine Sekunde später ist das leere Programm bereits sichtbar und läuft. Hurra für Computer, die so viel schneller werden!
Aber der Grund, warum ich so hin und weg bin, ist, dass ich normalerweise Visual Studio 2010 verwende, das sich überhaupt nicht so bissig anfühlt. Zugegeben, 7 Delphi ist ein viel kleineres System als Visual Studio 2010, aber es hat die haben Erscheinung alle die dort wirklich notwendigen Dinge aufweist: eine Steuerpalette, ein Formular - Designer, einen Code - Editor mit Code - Vervollständigung. Mir ist klar, dass die Sprache möglicherweise einfacher ist und die Codevervollständigung möglicherweise weniger leistungsfähig ist und die IDE möglicherweise nicht annähernd so erweiterbar und funktionsreich ist, aber dennoch: Ich verstehe nicht, wie (dh durch welchen Mechanismus) dies funktioniert Viele zusätzliche Funktionen (die ich möglicherweise noch nicht einmal ausgelöst habe) führen dazu, dass ein System wie Visual Studio im Vergleich immer träge wirkt.
Ich möchte Menschen, die Erfahrung mit der Arbeit mit Systemen haben, nach dem Maßstab von Visual Studio fragen: Was macht sie langsam? Sind es die Schichten auf Schichten von Abstraktionen, die erforderlich sind, um die Codebasis innerhalb der menschlichen Verständnisfähigkeiten zu halten? Ist es die Menge an Code, die durchlaufen werden muss? Ist es die moderne Tendenz zu zeitsparenden Ansätzen für Programmierer, die (umwerfend) hohe Kosten in der Abteilung für Taktzyklen / Speichernutzung verursachen?
quelle
Antworten:
Architektur-Astronautik
Visual Studio 2010 basiert auf Windows Presentation Foundation. Schauen Sie sich die Button-Klasse für WPF an. Es ist das 9. Kind einer Basisklasse. Es hat ungefähr 5 Seiten mit Eigenschaften, Methoden und Ereignissen. Hinter den Kulissen befinden sich weitere fünf Seiten mit Stildefinitionen, die die wunderschön abgerundeten Ecken und die subtilen Animationsübergänge beschreiben, wenn sich ein Mauszeiger darüber bewegt. Dies ist alles für etwas, das im Grunde genommen Text oder ein Bild anzeigt und ein Klickereignis erzeugt, wenn eine Maustaste herunterfällt.
Beenden Sie ein Programm wie Visual Studio an einer beliebigen Stelle. Schauen Sie sich den Stack-Trace an. Die Chancen stehen sehr gut, dass Sie 20 Ebenen tief im aufrufenden Stapel sind und dass fünf DLLs geladen wurden, um dorthin zu gelangen.
Vergleichen Sie nun diese beiden Dinge mit Delphi. Ich wette, Sie stellen fest, dass ein Delphi-Button nur 20 Eigenschaften, Methoden und Ereignisse enthält. Ich wette, die Delphi-IDE hat nur einen Stack-Trace mit einer Tiefe von 5-7 Ebenen. Denn wenn Computer langsamer waren, konnte man den Overhead von Visual Studio 2010 einfach nicht ertragen, ohne dass die IDE 40 Minuten brauchte, um zu starten :-)
Ist einer besser als der andere? Nun, ich kann einem Delphi-Programm im Allgemeinen sagen, wann es geladen wird, weil es flach aussieht, die Farben stummgeschaltet sind (vielleicht 8 Bit?) Und es keine subtilen Schattierungen oder Animationen gibt. Ich fühle mich heutzutage einfach "billig". Günstig, aber schnell.
Geht es uns besser? Das ist eine Frage für die Philosophen, nicht für die Programmierer.
quelle
Ich glaube, Sie haben eine Reihe davon erraten, aber ich möchte Ihnen den meiner Meinung nach größten Faktor anbieten, da ich an einer einigermaßen großen Codebasis gearbeitet habe (nicht sicher, ob sie so groß ist wie Visual Studio - in Millionen von Codezeilen) Kategorie und etwa tausend Plugins) seit etwa 10 Jahren und beobachtende Phänomene auftreten.
Es ist auch ein bisschen weniger kontrovers, da es nicht auf APIs oder Sprachfunktionen oder ähnliches eingeht. Diese beziehen sich auf "Kosten", die eher zu einer Debatte als zu "Ausgaben" führen können, und ich möchte mich auf "Ausgaben" konzentrieren.
Lose Koordination und Vermächtnis
Was ich beobachtet habe, ist, dass eine lose Koordination und ein langes Vermächtnis dazu neigen, eine Menge Müll anzusammeln.
Zum Beispiel fand ich in dieser Codebasis ungefähr einhundert Beschleunigungsstrukturen, von denen viele überflüssig sind.
Wir hätten gerne einen KD-Baum zum Beschleunigen einer Physik-Engine, einen anderen für eine neue Physik-Engine, die häufig parallel zur alten ausgeführt wird. Wir hätten Dutzende Implementierungen von Octrees für verschiedene Mesh-Algorithmen, einen weiteren KD-Baum zum Rendern , Kommissionierung usw. usw. usw. Dies sind alles große, sperrige Baumstrukturen, die zur Beschleunigung der Suche verwendet werden. Jeder einzelne kann Hunderte von Megabyte bis Gigabyte Speicher für eine Eingabe mit sehr durchschnittlicher Größe benötigen. Sie wurden nicht immer instanziiert und verwendet, aber zu einem bestimmten Zeitpunkt könnten sich 4 oder 5 von ihnen gleichzeitig im Speicher befinden.
Jetzt speicherten alle genau dieselben Daten, um die Suche nach ihnen zu beschleunigen. Sie können es sich wie die analoge alte Datenbank vorstellen, die alle ihre Felder in 20 verschiedenen redundanten Karten / Wörterbüchern / B + -Bäumen auf einmal speichert, die mit denselben Schlüsseln identisch organisiert sind und die alle ständig durchsucht. Jetzt nehmen wir 20-mal den Speicher und die Verarbeitung.
Darüber hinaus bleibt aufgrund der Redundanz nur wenig Zeit, um einen von ihnen mit dem damit verbundenen Wartungspreis zu optimieren, und selbst wenn dies der Fall wäre, hätte er nur 5% der Wirkung, die er im Idealfall erzielen würde.
Was verursacht dieses Phänomen? Lose Koordination war die häufigste Ursache, die ich sah. Viele Teammitglieder arbeiten häufig in ihren isolierten Ökosystemen und entwickeln oder verwenden Datenstrukturen von Drittanbietern, verwenden jedoch nicht dieselben Strukturen, die andere Teammitglieder verwendet haben, selbst wenn es sich um geradezu offensichtliche Duplikate genau derselben Bedenken handelte.
Was bewirkt, dass dieses Phänomen anhält? Vermächtnis und Kompatibilität waren die Hauptursache, die ich sah. Da wir die Kosten für die Implementierung dieser Datenstrukturen bereits bezahlt haben und große Mengen an Code von diesen Lösungen abhängig waren, war es oft zu riskant, sie auf weniger Datenstrukturen zu konsolidieren. Obwohl viele dieser Datenstrukturen konzeptionell hochgradig redundant waren, waren sie in ihren Schnittstellendesigns nicht immer annähernd identisch. Ihre Ersetzung wäre also eine große, riskante Änderung gewesen, anstatt sie nur Speicherplatz und Verarbeitungszeit in Anspruch nehmen zu lassen.
Speichereffizienz
In der Regel hängen die Speichernutzung und die Geschwindigkeit zumindest auf der Bulk-Ebene zusammen. Sie können langsame Software oft daran erkennen, wie sie den Speicher voll macht. Es ist nicht immer wahr, dass mehr Speicher zu einer Verlangsamung führt, da es auf "heißen" Speicher ankommt (auf welchen Speicher ständig zugegriffen wird - wenn ein Programm eine Schiffsladung Speicher verwendet, aber nur 1 Megabyte davon verwendet werden Zeit, dann ist es nicht so eine große Sache, geschwindigkeitsmäßig).
So können Sie die potenziellen Schweine basierend auf der Speichernutzung viel Zeit erkennen. Wenn eine Anwendung beim Start Dutzende bis Hunderte von Megabyte Speicher benötigt, ist dies wahrscheinlich nicht sehr effizient. Dutzende Megabyte mögen heutzutage klein erscheinen, wenn wir Gigabyte DRAM haben, aber die größten und langsamsten CPU-Caches liegen immer noch im Bereich von knappen Megabyte und die schnellsten liegen immer noch im Bereich von Kilobyte. Infolgedessen verbraucht ein Programm, das nur zum Starten 20 Megabyte benötigt und nichts tut, aus der Sicht des Hardware-CPU-Cache immer noch ziemlich viel Speicher, insbesondere wenn wiederholt und auf alle 20 Megabyte dieses Speichers zugegriffen wird häufig, während das Programm ausgeführt wird.
Lösung
Für mich besteht die Lösung darin, koordiniertere, kleinere Teams zu suchen, um Produkte zu bauen. Diese Teams können ihre "Ausgaben" nachverfolgen und vermeiden, immer und immer wieder dieselben Artikel zu "kaufen".
Kosten
Ich werde in die umstrittenere "Kostenseite" eintauchen, nur ein kleines bisschen mit einem "Ausgaben" -Phänomen, das ich beobachtet habe. Wenn eine Sprache ein unvermeidbares Preisschild für ein Objekt hat (wie eines, das Laufzeitreflexion bietet und keine zusammenhängende Zuordnung für eine Reihe von Objekten erzwingen kann), ist dieses Preisschild nur im Kontext eines sehr granularen Elements wie a teuer einzeln
Pixel
oderBoolean
.Aber ich sehe eine Menge Quellcode für Programme , die eine schwere Last bewältigen tun (zB: Umgang mit Hunderttausenden bis Millionen
Pixel
oderBoolean
Instanzen) , dass die Kosten einer solchen granularen Ebene zu bezahlen.Objektorientiertes Programmieren kann das irgendwie verschlimmern. Es sind jedoch nicht die Kosten für "Objekte" an sich oder gar OOP, sondern nur die Kosten, die auf einer so detaillierten Ebene eines jugendlichen Elements gezahlt werden, das millionenfach instanziiert wird.
Das sind also die anderen Phänomene der Kosten und Ausgaben, die ich beobachte. Die Kosten betragen ein paar Cent, aber ein paar Cent summieren sich, wenn wir eine Million Dosen Soda einzeln kaufen, anstatt mit einem Hersteller über einen Großeinkauf zu verhandeln.
Die Lösung hier für mich ist "Großeinkauf". Objekte sind auch in Sprachen, die jeweils ein paar Cent kosten, vollkommen in Ordnung, vorausgesetzt, diese Kosten werden für das analoge Äquivalent einer Getränkedose nicht millionenfach einzeln gezahlt.
Vorzeitige Optimierung
Ich mochte die Formulierung, die Knuth hier verwendete, nie so recht, weil "vorzeitige Optimierung" die realen Produktionsprogramme selten schneller macht. Einige interpretieren dies als "frühzeitig optimieren", wenn Knuth eher "ohne die richtigen Kenntnisse / Erfahrungen optimieren, um die tatsächlichen Auswirkungen auf die Software zu kennen" meinte. Wenn überhaupt, wird der praktische Effekt einer vorzeitigen Optimierung die Software häufig verlangsamen , da aufgrund der verschlechterten Wartbarkeit nur wenig Zeit bleibt , um die wirklich wichtigen kritischen Pfade zu optimieren .
Dies ist das letzte Phänomen, das ich beobachtete, als Entwickler, die beim Kauf einer einzigen Dose Soda ein paar Cent sparen wollten, nie wieder ein Haus kauften oder noch schlimmer, all ihre Zeit damit verschwendeten, ein paar Cent (oder noch schlimmer, imaginäre Cent) zu kneifen Unverständnis ihres Compilers oder der Architektur der Hardware), als Milliarden von Dollar verschwenderisch an anderer Stelle ausgegeben wurden.
Die Zeit ist sehr begrenzt. Wenn wir also versuchen, Absolutes zu optimieren, ohne über die richtigen Kontextinformationen zu verfügen, haben wir oftmals nicht die Möglichkeit, die wirklich wichtigen Stellen zu optimieren. Aus praktischen Gründen würde ich sagen, dass "vorzeitige Optimierung Software viel langsamer macht. "
Das Problem ist, dass es Entwicklertypen gibt, die das, was ich oben über Objekte geschrieben habe, nehmen und versuchen, einen Codierungsstandard zu etablieren, der die objektorientierte Programmierung oder etwas Verrücktes dieser Art verbietet. Effektive Optimierung ist eine effektive Priorisierung, und es ist absolut wertlos, wenn wir in einem Meer von Wartungsproblemen ertrinken.
quelle
--force
von Managern, die schreien "Sie werden gefeuert, wenn Sie dies nicht bis morgen implementieren", die Jahre guter Softwareentwicklungspraktiken, TDD, Komponententests und aller menschlichen und vernünftigen Programmierprinzipien zunichte machen und zwei weitere Male, in denen Sie müde waren ... dieser Typ, der die Firma verrückt gemacht hat, weil er ohne Grund entlassen wurde und die Codebasis durcheinander gebracht hat ... diese nicht mehr erhältlichen Bibliotheken, die Sie nie aktualisiert haben ... und hier haben Sie sie: die köstliche Spaghetti-Codebasis und aufgeblähte Software. Guten Appetit