Ist vorzeitige Optimierung wirklich die Wurzel allen Übels?


215

Ein Kollege von mir hat heute eine Klasse namens geschrieben ThreadLocalFormat, die im Grunde genommen Instanzen von Java-Format-Klassen in ein Thread-Local verschoben hat, da sie nicht thread-sicher und "relativ teuer" zu erstellen sind. Ich schrieb einen Schnelltest und errechnete, dass ich 200.000 Instanzen pro Sekunde erstellen könnte, und fragte ihn, ob er so viele erstellen könne, auf die er antwortete, "bei weitem nicht so viele". Er ist ein großartiger Programmierer und jeder im Team ist hoch qualifiziert, sodass wir den resultierenden Code problemlos verstehen können. Es handelte sich jedoch eindeutig um einen Optimierungsfall, bei dem kein wirklicher Bedarf besteht. Auf meine Bitte hin hat er den Code zurückgesetzt. Was denkst du? Handelt es sich um "vorzeitige Optimierung" und wie schlimm ist es wirklich?


23
Ich denke, Sie müssen zwischen vorzeitiger und unnötiger Optimierung unterscheiden. Verfrüht bedeutet für mich "zu früh im Lebenszyklus", unnötigerweise bedeutet dies "keinen signifikanten Mehrwert". IMO, die Forderung nach einer späten Optimierung impliziert ein schlechtes Design.

110
Ja, aber das Böse ist ein Polynom und hat viele Wurzeln, von denen einige komplex sind.
dan_waterworth

7
Man sollte bedenken, dass Knuth dieses 1974 geschrieben hat. In den siebziger Jahren war es nicht so einfach, langsame Programme zu schreiben, wie es heutzutage ist. Er schrieb mit Pascal im Sinn und nicht mit Java oder PHP.
2.

4
Die Wurzel allen Übels ist Gier.
Tulains Córdova

12
@ceving In den 70ern war es so einfach wie heute, langsame Programme zu schreiben. Wenn Sie den falschen Algorithmus oder die falsche Datenstruktur wählen, dann ist BAM! Überall schlechte Leistung. Man könnte anders herum argumentieren. Heutzutage sind das viel mehr Werkzeuge und sollten unentschuldbar sein, dass ein Programmierer immer noch Software schreibt, die am grundlegendsten unter Sicherungsoperationen leidet. Parallelität wurde fast zur Ware und wir leiden immer noch. Langsame Leistung kann nicht auf die Sprache oder das Werkzeug oder die CPU oder den Speicher zurückgeführt werden. Es ist ein empfindliches Gleichgewicht zwischen so vielen Dingen, weshalb es fast unmöglich ist, frühzeitig zu optimieren.
Alex

Antworten:


322

Beachten Sie unbedingt das vollständige Zitat:

Wir sollten kleine Wirkungsgrade vergessen, sagen wir in 97% der Fälle: Vorzeitige Optimierung ist die Wurzel allen Übels. Dennoch sollten wir unsere Chancen bei diesen kritischen 3% nicht verpassen.

Dies bedeutet, dass Sie mangels gemessener Leistungsprobleme nicht optimieren sollten, da Sie glauben, dass Sie einen Leistungsgewinn erzielen werden. Es gibt offensichtliche Optimierungen (z. B. keine Verkettung von Zeichenfolgen in einer engen Schleife), aber alles, was nicht trivial klar ist, sollte vermieden werden, bis es gemessen werden kann.

Das größte Problem bei der "vorzeitigen Optimierung" besteht darin, dass sie unerwartete Fehler verursachen und viel Zeit verschwenden kann.


7
Da ich von Donald Knuth bin, wäre ich nicht überrascht, wenn er Beweise dafür hätte. BTW, Src: Structured Programming mit go to Statements, ACM Journal Computing Surveys, Bd. 6, Nr. 4, Dezember 1974. S.268. citeseerx.ist.psu.edu/viewdoc/…
mctylr

28
... Ein guter Programmierer wird durch solche Überlegungen nicht zur Selbstzufriedenheit gebracht, er wird klug sein, sich den kritischen Code genau anzuschauen. aber erst, nachdem dieser Code identifiziert wurde (Rest des vollständigeren Zitats)
mctylr

21
Ich habe heute von einem 20-köpfigen Mitarbeiter erfahren, dass die Verwendung von a HashSetanstelle von a eine Listvorzeitige Optimierung war. Der fragliche Anwendungsfall war eine statisch initialisierte Sammlung, deren einziger Zweck darin bestand, als Nachschlagetabelle zu dienen. Ich glaube nicht, dass ich mich irre, wenn ich sage, dass es einen Unterschied zwischen der Auswahl des richtigen Tools für den Job und der vorzeitigen Optimierung gibt. Ich denke, Ihr Beitrag bestätigt diese Philosophie: There are obvious optimizations...anything that isn't trivially clear optimization should be avoided until it can be measured.Die Optimierung eines HashSets wurde sorgfältig gemessen und dokumentiert.
Zerstöre den

9
@crush: yes: Setist auch semantisch korrekter und informativer als List, es geht also um mehr als den Optimierungsaspekt.
Erik Allik

7
Ich möchte hinzufügen, dass eine vorzeitige Optimierung nicht mit dem Entwurf Ihrer gesamten Anwendungsarchitektur verwechselt werden sollte, um im Allgemeinen schnell zu laufen, skaliert zu werden und einfach zu optimieren.
Erik Allik

111

Vorzeitige Mikrooptimierungen sind die Wurzel allen Übels, weil Mikrooptimierungen den Kontext auslassen. Sie verhalten sich fast nie so, wie sie es erwarten.

Was sind einige gute frühe Optimierungen in der Reihenfolge der Wichtigkeit:

  • Architekturoptimierungen (Anwendungsstruktur, Art der Komponenten- und Ebenenbildung)
  • Datenflussoptimierungen (innerhalb und außerhalb der Anwendung)

Einige Optimierungen für den mittleren Entwicklungszyklus:

  • Datenstrukturen, führen Sie neue Datenstrukturen ein, die bei Bedarf eine bessere Leistung oder einen geringeren Overhead aufweisen
  • Algorithmen (jetzt ist es ein guter Zeitpunkt, sich zwischen quicksort3 und heapsort zu entscheiden ;-))

Einige Optimierungen am Ende des Entwicklungszyklus

  • Finden von Code-Hotpots (enge Schleifen, die optimiert werden sollten)
  • Profilbasierte Optimierungen von rechnerischen Teilen des Codes
  • Mikrooptimierungen können jetzt so durchgeführt werden, wie sie im Kontext der Anwendung durchgeführt werden, und ihre Auswirkung kann korrekt gemessen werden.

Nicht alle frühen Optimierungen sind böse, Mikrooptimierungen sind böse, wenn sie zum falschen Zeitpunkt im Entwicklungslebenszyklus durchgeführt werden , da sie die Architektur beeinträchtigen, die anfängliche Produktivität beeinträchtigen, in Bezug auf die Leistung irrelevant sein oder sich am Ende sogar nachteilig auswirken können der Entwicklung aufgrund unterschiedlicher Umgebungsbedingungen.

Wenn Leistung von Belang ist (und immer sein sollte), denken Sie immer groß . Leistung ist ein größeres Bild und nicht etwa: Soll ich int oder long verwenden ? Wählen Sie Top-Down, wenn Sie mit Leistung anstelle von Bottom-Up arbeiten .


"Optimierung: Ihr schlimmster Feind", von Joseph M. Newcomer: flounder.com/optimization.htm
Ron Ruble

53

Optimierung ohne Erstmessung ist fast immer verfrüht.

Ich glaube, das stimmt in diesem Fall und auch im allgemeinen Fall.


Hier hier! Eine nicht berücksichtigte Optimierung macht Code nicht mehr wartbar und ist häufig die Ursache für Leistungsprobleme. Beispiel: Sie führen ein Programm mit mehreren Threads durch, weil Sie sich vorstellen, dass es die Leistung verbessern könnte. Die eigentliche Lösung wären jedoch mehrere Prozesse gewesen, deren Implementierung jetzt zu komplex ist.
James Anderson

es sei denn, es ist dokumentiert.
Nawfal

Ja. stimme voll und ganz zu. Es muss zuerst gemessen werden. Es ist unmöglich zu wissen, wo die Engpässe liegen, bis Sie eine End-to-End-Prüfung durchführen und die einzelnen Schritte messen.
Oliver Watkins

Maße können lügen. Ich habe erfahrene Spezialisten gesehen, die Wochen damit verbracht haben, Spuren zu lesen und Profile zu erstellen, um an eine Wand zu stoßen, an der sie dachten, es gäbe nichts mehr zu gewinnen. Dann habe ich den gesamten Code durchgelesen und in wenigen Stunden einige ganzheitliche Änderungen vorgenommen, um eine 10-fache Verbesserung zu erzielen. Die Profile zeigten keine Hot-Paths, da der gesamte Code schlecht gestaltet war. Ich habe auch gesehen, wie Profiler Hotpaths beanspruchten, auf denen es keine hätte geben dürfen. Eine Person, die "misst", hätte den Hotpath optimiert, aber sie hätte erkennen müssen, dass der Hotpath ein Symptom für anderen schlechten Code ist.
Bengie

42

Optimierung ist "böse", wenn sie verursacht:

  • weniger klarer Code
  • deutlich mehr Code
  • weniger sicherer Code
  • verschwendete Programmiererzeit

In Ihrem Fall scheint es, als wäre bereits ein wenig Zeit für Programmierer aufgewendet worden, der Code war nicht zu komplex (eine Vermutung aus Ihrem Kommentar, die jeder im Team verstehen könnte), und der Code ist ein bisschen zukunftssicherer (seiend) thread safe jetzt, wenn ich deine beschreibung verstanden habe). Klingt nur ein bisschen böse. :)


4
Nur wenn die Kosten gemäß Ihren Aufzählungspunkten höher sind als der amortisierte Wert, der geliefert wurde. Oft bringt Komplexität einen Wert mit sich, und in diesen Fällen kann man ihn so einkapseln, dass er Ihre Kriterien erfüllt. Es wird auch wiederverwendet und bietet weiterhin mehr Wert.

1
Die ersten beiden Punkte sind für mich die wichtigsten, wobei der vierte Punkt eine negative Folge der vorzeitigen Optimierung ist. Insbesondere ist es eine rote Fahne, wenn ich jemanden sehe, der Features aus einer Standardbibliothek erneut implementiert. Ich habe einmal gesehen, wie jemand benutzerdefinierte Routinen für die Manipulation von Zeichenfolgen implementierte, weil er befürchtete, die eingebauten Befehle seien zu langsam.
jhocking

8
Das Sichern von Code-Threads ist keine Optimierung.
Mattnz

38

Ich bin überrascht, dass diese Frage 5 Jahre alt ist, und dennoch hat niemand mehr von Knuth geschrieben, als ein paar Sätze. Die paar Absätze, die das berühmte Zitat umgeben, erklären es ziemlich gut. Das Papier, das zitiert wird, heißt " Structured Programming with go to Statements " und handelt, obwohl es fast 40 Jahre alt ist, von einer Kontroverse und einer Softwarebewegung, die beide nicht mehr existieren, und enthält Beispiele in Programmiersprachen, die viele Menschen noch nie gesehen haben Davon gehört, dass eine überraschend große Menge von dem, was gesagt wurde, immer noch zutrifft.

Hier ist ein größeres Zitat (ab Seite 8 des PDF, Seite 268 im Original):

Die Geschwindigkeitsverbesserung von Beispiel 2 zu Beispiel 2a beträgt nur etwa 12%, und viele Leute würden dies als unbedeutend bezeichnen. Die konventionelle Weisheit vieler heutiger Software-Ingenieure verlangt, die Effizienz im Kleinen zu ignorieren. Aber ich glaube, dies ist einfach eine Überreaktion auf die Missbräuche, die von hochtrabenden Programmierern begangen werden, die ihre "optimierten" Programme nicht debuggen oder warten können. In etablierten Ingenieurdisziplinen wird eine 12% ige Verbesserung, die leicht zu erzielen ist, niemals als geringfügig angesehen. und ich glaube, dass der gleiche Standpunkt in der Softwareentwicklung gelten sollte. Natürlich würde ich nicht die Mühe machen, solche Optimierungen an einem einzigen Job vorzunehmen, aber wenn es um die Erstellung von Qualitätsprogrammen geht, möchte ich mich nicht auf Tools beschränken, die mir solche Effizienz verweigern.

Es besteht kein Zweifel, dass der Gral der Effizienz zu Missbrauch führt. Programmierer verschwenden enorm viel Zeit damit, über die Geschwindigkeit unkritischer Teile ihrer Programme nachzudenken oder sich Gedanken zu machen, und diese Effizienzversuche wirken sich bei der Prüfung von Debugging und Wartung stark negativ aus. Wir sollten kleine Wirkungsgrade vergessen, sagen wir in 97% der Fälle: Vorzeitige Optimierung ist die Wurzel allen Übels.

Dennoch sollten wir unsere Chancen bei diesen kritischen 3% nicht verpassen. Ein guter Programmierer wird durch solche Überlegungen nicht zur Selbstzufriedenheit gebracht, er wird klug sein, sich den kritischen Code genau anzuschauen. aber erst nachdem dieser Code identifiziert wurde. Es ist oft ein Fehler, von vornherein zu beurteilen, welche Teile eines Programms wirklich kritisch sind, da die universelle Erfahrung von Programmierern, die Messwerkzeuge verwendet haben, darin bestand, dass ihre intuitiven Vermutungen fehlschlagen.

Ein weiteres gutes Stück von der vorherigen Seite:

Mein eigener Programmierstil hat sich natürlich im letzten Jahrzehnt den Trends der Zeit angepasst (z. B. bin ich nicht mehr so ​​knifflig und benutze weniger Go's), aber die große Änderung in meinem Stil ist darauf zurückzuführen zu diesem inneren Schleifenphänomen. Ich betrachte jetzt jede Operation in einer kritischen inneren Schleife mit einem extrem kritischen Auge und versuche, meine Programm- und Datenstruktur (wie beim Wechsel von Beispiel 1 zu Beispiel 2) so zu ändern, dass einige der Operationen eliminiert werden können. Die Gründe für diesen Ansatz sind folgende: a) Es dauert nicht lange, da die innere Schleife kurz ist; b) die Auszahlung ist real; und c) ich kann es mir dann leisten, in den anderen Teilen meiner Programme, die daher besser lesbar und leichter zu schreiben und zu debuggen sind, weniger effizient zu sein.


20

Ich habe oft gesehen, dass dieses Zitat verwendet wurde, um offensichtlich schlechten Code oder Code zu rechtfertigen, der, obwohl seine Leistung nicht gemessen wurde, wahrscheinlich recht einfach schneller gemacht werden könnte, ohne die Codegröße zu erhöhen oder seine Lesbarkeit zu beeinträchtigen.

Im Allgemeinen halte ich frühe Mikrooptimierungen für eine schlechte Idee. Makrooptimierungen (z. B. die Auswahl eines O (log N) -Algorithmus anstelle von O (N ^ 2)) sind jedoch häufig sinnvoll und sollten frühzeitig durchgeführt werden, da es möglicherweise verschwenderisch ist, einen O (N ^ 2) -Algorithmus zu schreiben und Werfen Sie es dann vollständig weg, und verwenden Sie die Methode O (log N).

Beachten Sie, dass die Wörter sein können : Wenn der O (N ^ 2) -Algorithmus einfach und leicht zu schreiben ist, können Sie ihn später ohne viel Schuldgefühl wegwerfen, wenn er sich als zu langsam herausstellt. Wenn jedoch beide Algorithmen ähnlich komplex sind oder wenn die erwartete Arbeitslast so hoch ist, dass Sie bereits wissen, dass Sie die schnellere benötigen, ist eine frühzeitige Optimierung eine fundierte technische Entscheidung, die Ihre gesamte Arbeitslast auf lange Sicht reduziert.

Daher denke ich im Allgemeinen, dass der richtige Ansatz darin besteht, herauszufinden, welche Optionen Sie haben, bevor Sie mit dem Schreiben von Code beginnen, und den besten Algorithmus für Ihre Situation zu wählen. Am wichtigsten ist jedoch, dass der Ausdruck "vorzeitige Optimierung ist die Wurzel allen Übels" keine Entschuldigung für Unwissenheit ist. Karriereentwickler sollten eine allgemeine Vorstellung davon haben, wie hoch die allgemeinen Betriebskosten sind. sie sollten zum Beispiel wissen,

  • Saiten kosten mehr als Zahlen
  • dass dynamische Sprachen viel langsamer sind als statisch typisierte Sprachen
  • die Vorteile von Array- / Vektorlisten gegenüber verknüpften Listen und umgekehrt
  • wann eine Hashtabelle verwendet werden soll, wann eine sortierte Karte verwendet werden soll und wann ein Heap verwendet werden soll
  • dass (wenn sie mit mobilen Geräten arbeiten) "double" und "int" auf Desktops eine ähnliche Leistung haben (FP kann sogar schneller sein), aber "double" auf mobilen Low-End-Geräten ohne FPUs hundertmal langsamer sein kann;
  • Das Übertragen von Daten über das Internet ist langsamer als der Festplattenzugriff, Festplatten sind erheblich langsamer als RAM, RAM ist viel langsamer als der L1-Cache und die Register, und Internetvorgänge können auf unbestimmte Zeit blockiert werden (und jederzeit fehlschlagen).

Entwickler sollten mit einer Toolbox von Datenstrukturen und Algorithmen vertraut sein, damit sie problemlos die richtigen Tools für den Job verwenden können.

Mit viel Wissen und einer persönlichen Toolbox können Sie nahezu mühelos optimieren. Es ist böse, viel Mühe in eine Optimierung zu stecken, die möglicherweise unnötig ist (und ich gebe zu, mehr als einmal in diese Falle zu tappen). Aber wenn die Optimierung so einfach ist wie das Auswählen einer Menge / einer Hashtabelle anstelle eines Arrays oder das Speichern einer Liste von Zahlen in double [] anstelle von string [], warum dann nicht? Ich bin mir nicht sicher, ob ich hier mit Knuth nicht einverstanden bin, aber ich glaube, er hat von Low-Level-Optimierung gesprochen, während ich von High-Level-Optimierung spreche.

Denken Sie daran, dass dieses Zitat ursprünglich aus dem Jahr 1974 stammt. Im Jahr 1974 waren Computer langsam und die Rechenleistung teuer, was einigen Entwicklern die Tendenz gab, Zeile für Zeile zu optimieren. Ich glaube, Knuth hat sich dagegen gewehrt. Er sagte nicht "mach dir überhaupt keine Sorgen um die Leistung", denn 1974 wäre das nur verrücktes Gerede. Knuth erklärte, wie man optimiert; Kurz gesagt, man sollte sich nur auf die Engpässe konzentrieren, und bevor Sie dies tun, müssen Sie Messungen durchführen, um die Engpässe zu finden.

Beachten Sie, dass Sie die Engpässe erst finden können, wenn Sie ein zu messendes Programm geschrieben haben. Dies bedeutet, dass einige Leistungsentscheidungen getroffen werden müssen , bevor etwas zu messen ist. Manchmal ist es schwierig, diese Entscheidungen zu ändern, wenn Sie sie falsch verstehen. Aus diesem Grund ist es gut, eine allgemeine Vorstellung davon zu haben, was Dinge kosten, damit Sie vernünftige Entscheidungen treffen können, wenn keine festen Daten verfügbar sind.

Wie früh die Optimierung beginnt und inwieweit Sie sich um die Leistung sorgen müssen, hängt vom jeweiligen Job ab. Wenn Sie Skripte schreiben, die Sie nur ein paar Mal ausführen, ist es in der Regel reine Zeitverschwendung, sich Gedanken über die Leistung zu machen. Wenn Sie jedoch für Microsoft oder Oracle arbeiten und an einer Bibliothek arbeiten, die Tausende anderer Entwickler auf tausende verschiedene Arten verwenden werden, lohnt es sich möglicherweise, sie zu optimieren, damit Sie die gesamte Bandbreite abdecken können Use Cases effizient nutzen. Trotzdem muss das Leistungsbedürfnis immer gegen das Bedürfnis nach Lesbarkeit, Wartbarkeit, Eleganz, Erweiterbarkeit usw. abgewogen werden.


2
Amen. Die vorzeitige Optimierung wird heutzutage von Menschen viel zu großzügig herumgeschleudert, die versuchen, die Verwendung des falschen Tools für den Job zu rechtfertigen. Wenn Sie das richtige Werkzeug für den Job im Voraus kennen, gibt es keine Entschuldigung, es nicht zu verwenden.
Crush

13

Persönlich in einem so bedeckt vorherigen Thread , ich glaube nicht , dass frühe Optimierung ist schlecht in Situationen , in denen Sie wissen , dass Sie Performance - Probleme getroffen. Zum Beispiel schreibe ich Oberflächenmodellierungs- und Analysesoftware, in der ich mich regelmäßig mit zig Millionen von Entitäten befasse. Das Planen einer optimalen Leistung in der Entwurfsphase ist der späten Optimierung eines schwachen Entwurfs weit überlegen.

Eine weitere zu berücksichtigende Frage ist, wie sich Ihre Anwendung in Zukunft skalieren lässt. Wenn Sie davon ausgehen, dass Ihr Code eine lange Lebensdauer hat, ist die Optimierung der Leistung in der Entwurfsphase ebenfalls eine gute Idee.

Nach meiner Erfahrung bietet die späte Optimierung magere Belohnungen zu einem hohen Preis. Die Optimierung in der Entwurfsphase durch Algorithmusauswahl und Optimierung ist viel besser. Abhängig davon, dass ein Profiler versteht, wie Ihr Code funktioniert, ist dies kein guter Weg, um leistungsstarken Code zu erhalten. Sie sollten dies im Voraus wissen.


Das ist sicherlich richtig. Ich vermute, vorzeitige Optimierung ist, wenn Code aufgrund unklarer Vorteile auf eine Weise komplexer / schwer verständlich gemacht wird, die nur lokale Auswirkungen hat (Design hat globale Auswirkungen).
Paul de Vrieze

2
Es geht nur um Definitionen. Optimierung ist für mich das Entwerfen und Schreiben von Code, um eine optimale Leistung zu erzielen. Die meisten hier scheinen es so zu behandeln, als würden sie mit dem Code herumhacken, wenn sie feststellen, dass er nicht schnell oder effizient genug ist. Ich verbringe viel Zeit mit der Optimierung, normalerweise während des Designs.

3
Optimieren Sie das Design am Anfang, Optimieren Sie den Code am Ende.
BCS

Sie sind in Ihrem Fall ganz richtig, aber für die meisten Programmierer glauben sie, dass sie Leistungsprobleme haben werden, aber in Wirklichkeit werden sie es nie. Viele sorgen sich um die Leistung bei der Arbeit mit 1000 Entitäten, wenn ein grundlegender Test der Daten zeigt, dass die Leistung in Ordnung ist, bis sie 1000000 Entitäten erreicht haben.
Toby Allen

1
"Die Planung für eine optimale Leistung in der Entwurfsphase ist der späten Optimierung eines schwachen Entwurfs weit überlegen" und "späte Optimierung bietet magere Belohnungen zu einem hohen Preis" - sehr gut ausgedrückt! Wahrscheinlich nicht für 97% aller produzierten Systeme, aber für viele - beunruhigend viele - Systeme.
Olof Forshell

10

Tatsächlich habe ich gelernt, dass vorzeitige Nichtoptimierung häufiger die Wurzel allen Übels ist.

Beim Schreiben von Software treten zunächst Probleme auf, wie Instabilität, eingeschränkte Funktionen, schlechte Bedienbarkeit und schlechte Leistung. All dies wird normalerweise behoben, wenn die Software ausgereift ist.

Alles außer Leistung. Niemand scheint sich um Leistung zu kümmern. Der Grund ist einfach: Wenn eine Software abstürzt, wird jemand den Fehler beheben und das ist es, wenn ein Feature fehlt, wird jemand es implementieren und fertig, wenn die Software eine schlechte Leistung hat, liegt es in vielen Fällen nicht an einer fehlenden Mikrooptimierung, sondern daran wegen schlechten Designs und niemand wird das Design der Software berühren. JE.

Schau dir Bochs an. Es ist langsam wie die Hölle. Wird es jemals schneller werden? Vielleicht, aber nur im Bereich einiger Prozent. Es wird niemals eine Leistung erzielen, die mit Virtualisierungssoftware wie VMWare oder VBox oder sogar QEMU vergleichbar ist. Weil es von Natur aus langsam ist!

Wenn das Problem einer Software darin besteht, dass sie langsam ist, dann weil sie SEHR langsam ist und dies nur durch eine Verbesserung der Leistung um eine Vielzahl von Faktoren behoben werden kann. + 10% machen eine langsame Software einfach nicht schnell. Und bei späteren Optimierungen werden Sie in der Regel nicht mehr als 10% erhalten.

Wenn also die Leistung für Ihre Software wichtig ist, sollten Sie dies von Anfang an bei der Entwicklung berücksichtigen, anstatt zu denken: "Oh ja, es ist langsam, aber das können wir später verbessern." Weil du nicht kannst!

Ich weiß, dass das nicht wirklich zu Ihrem speziellen Fall passt, aber es beantwortet die allgemeine Frage "Ist vorzeitige Optimierung wirklich die Wurzel allen Übels?" - mit einem klaren NEIN.

Jede Optimierung, wie jede Funktion usw. muss sorgfältig entworfen und sorgfältig implementiert werden. Dazu gehört auch eine angemessene Bewertung von Kosten und Nutzen. Optimieren Sie einen Algorithmus nicht, um hier und da einige Zyklen zu sparen, wenn dadurch kein messbarer Leistungsgewinn erzielt wird.

Nur als Beispiel: Sie können die Leistung einer Funktion verbessern, indem Sie sie inline setzen und möglicherweise eine Handvoll Zyklen einsparen. Gleichzeitig erhöhen Sie wahrscheinlich die Größe Ihrer ausführbaren Datei und erhöhen die Wahrscheinlichkeit von TLB- und Cache-Ausfällen, die Tausende von Zyklen oder sogar Kosten verursachen Paging-Vorgänge, die die Leistung vollständig beeinträchtigen. Wenn Sie diese Dinge nicht verstehen, kann Ihre "Optimierung" schlecht ausfallen.

Dumme Optimierung ist schlimmer als "vorzeitige" Optimierung, aber beide sind immer noch besser als vorzeitige Nichtoptimierung.


6

Es gibt zwei Probleme mit PO: Erstens, die Entwicklungszeit, die für nicht wesentliche Arbeiten verwendet wird, die zum Schreiben weiterer Funktionen oder zum Beheben weiterer Fehler verwendet werden könnten, und zweitens, das falsche Sicherheitsgefühl, dass der Code effizient ausgeführt wird. PO beinhaltet oft die Optimierung von Code, der nicht zum Flaschenhals wird, während der Code, der dazu führt, nicht bemerkt wird. Das "vorzeitige" Bit bedeutet, dass die Optimierung durchgeführt wird, bevor ein Problem unter Verwendung geeigneter Messungen identifiziert wird.

Im Grunde klingt das nach vorzeitiger Optimierung, aber ich würde es nicht unbedingt zurücksetzen, wenn es keine Bugs einführt - schließlich wurde es jetzt optimiert (!)


Du meinst "mehr Tests schreiben" anstatt "mehr Features schreiben", oder? :)
Greg Hewgill

1
Weitere Funktionen
erfordert

Ähm ja! Genau das habe ich gemeint ...
Harriyott

2
Der Code führt eine weitere Komplexität ein und wird wahrscheinlich nicht universell verwendet. Das Sichern (und ähnliches) hält den Code sauber.
Paul de Vrieze

3

Ich glaube, Mike Cohn nennt das "Vergolden" des Codes - das heißt, er verbringt Zeit mit Dingen, die nett sein könnten, aber nicht notwendig sind.

Er riet davon ab.

PS: "Vergolden" könnte in Bezug auf die Funktionalität ein Kinderspiel sein. Wenn Sie sich den Code ansehen, handelt es sich um unnötige Optimierungen, zukunftssichere Klassen usw.


2
Ich denke, "Vergolden" unterscheidet sich von Optimierungen. Bei Optimierungen geht es im Allgemeinen darum, die bestmögliche Leistung zu erzielen, während es beim "Vergolden" darum geht, die "Schnickschnack" (alle zusätzlichen Funktionen) hinzuzufügen, die für das Produkt nicht kritisch sind, die aber cool aussehen / sich cool anfühlen.
Scott Dorman

3

Da es kein Problem gibt, den Code zu verstehen, kann dieser Fall als Ausnahme angesehen werden.

Im Allgemeinen führt die Optimierung jedoch zu weniger lesbarem und verständlichem Code und sollte nur bei Bedarf angewendet werden. Ein einfaches Beispiel: Wenn Sie wissen, dass Sie nur ein paar Elemente sortieren müssen, verwenden Sie BubbleSort. Wenn Sie jedoch den Verdacht haben, dass die Elemente zunehmen könnten und Sie nicht wissen, wie viel es ist, ist die Optimierung mit QuickSort (zum Beispiel) nicht schlecht, sondern ein Muss. Und dies sollte bei der Gestaltung des Programms berücksichtigt werden.


1
Stimme nicht zu Ich würde sagen, niemals eine Blasensorte verwenden. Quicksort hat sich zu einem Defacto-Standard entwickelt, ist gut verstanden und in allen Szenarien so einfach zu implementieren wie eine Blasensortierung. Der niedrigste gemeinsame Nenner ist nicht mehr so ​​niedrig;)

1
Für eine wirklich kleine Anzahl von Elementen kann die für die Quicksortierung erforderliche Rekursion sie langsamer machen als eine anständige Bubblesortierung. Ganz zu schweigen davon, dass eine Bubblesortierung im schlimmsten Fall der Quicksortierung (
dh

Ja, aber das ist nur ein Beispiel für die Auswahl von Algorithmen für unterschiedliche Anforderungen;)

Stimmt, aber ich hätte QuickSort als Standard-Sortierung. Wenn ich dachte, dass bubblesort die Leistung verbessern würde, wäre dies eine Optimierung und nicht umgekehrt. Ich wähle QuickSort als Standardeinstellung, weil es gut verstanden und im Allgemeinen besser ist.

2
Meine Vorstellung von einer Standardsortierung ist, was immer mir die Bibliothek gibt (qsort (), .sort (), (sort ...), was auch immer).
David Thornley

3

Ich habe festgestellt, dass das Problem mit der vorzeitigen Optimierung meistens auftritt, wenn vorhandener Code neu geschrieben wird, um schneller zu sein. Ich kann sehen, dass es ein Problem sein könnte, zunächst eine verschlungene Optimierung zu schreiben, aber meistens sehe ich eine verfrühte Optimierung, die ihren hässlichen Kopf in der Korrektur dessen aufrichtet, was nicht (bekanntermaßen) kaputt ist.

Und das schlimmste Beispiel dafür ist, wenn ich jemanden sehe, der Features aus einer Standardbibliothek erneut implementiert. Das ist eine große rote Fahne. Ich habe einmal gesehen, wie jemand benutzerdefinierte Routinen für die Manipulation von Zeichenfolgen implementierte, weil er befürchtete, die eingebauten Befehle seien zu langsam.

Dies führt dazu, dass Code schwerer zu verstehen ist (schlecht) und viel Zeit für die Arbeit benötigt wird, was wahrscheinlich nicht nützlich ist (schlecht).


3

Aus einer anderen Perspektive ist es meine Erfahrung, dass die meisten Programmierer / Entwickler keinen Erfolg planen und der "Prototyp" fast immer Release 1.0 wird. Ich habe Erfahrung aus erster Hand mit 4 verschiedenen Originalprodukten, bei denen das elegante, sexy und hochfunktionale Front-End (im Grunde die Benutzeroberfläche) zu einer weit verbreiteten Akzeptanz und Begeisterung der Benutzer geführt hat. Bei jedem dieser Produkte schlichen sich Leistungsprobleme innerhalb relativ kurzer Zeit (1 bis 2 Jahre) ein, insbesondere als größere, anspruchsvollere Kunden begannen, das Produkt zu übernehmen. Sehr bald dominierte die Leistung die Themenliste, obwohl die Entwicklung neuer Funktionen die Prioritätenliste des Managements dominierte. Die Kunden wurden immer frustrierter, als jede Veröffentlichung neue Funktionen hinzufügte, die sich gut anhörten, aber aufgrund von Leistungsproblemen fast nicht zugänglich waren.

Sehr grundlegende Design- und Implementierungsfehler, die beim "Prototyp" keine oder nur geringe Bedeutung hatten, wurden zu großen Hindernissen für den langfristigen Erfolg der Produkte (und der Unternehmen).

Ihre Kundendemo kann mit XML-DOMs, SQL Express und vielen clientseitig zwischengespeicherten Daten auf Ihrem Laptop großartig aussehen und Leistung bringen. Wenn Sie erfolgreich sind, stürzt das Produktionssystem wahrscheinlich einen Brennvorgang ab.

1976 diskutierten wir immer noch über die optimalen Methoden zur Berechnung einer Quadratwurzel oder zum Sortieren eines großen Arrays, und Don Knuths Sprichwort richtete sich auf den Fehler, sich darauf zu konzentrieren, diese Art von Routine auf niedriger Ebene zu Beginn des Entwurfsprozesses zu optimieren, anstatt sich auf die Lösung des Problems zu konzentrieren und dann die lokalisierten Codebereiche zu optimieren.

Wenn man das Sprichwort wiederholt, um zu entschuldigen, dass kein effizienter Code (C ++, VB, T-SQL oder andere) geschrieben wurde, oder um den Datenspeicher nicht richtig zu entwerfen oder die Netzwerkarchitektur nicht zu berücksichtigen, dann demonstrieren sie IMO nur a sehr flaches Verständnis für die wahre Natur unserer Arbeit. Strahl


1
Haha, oder wenn die Demo mit drei Usern mit tausend zu Release 1.0 wird.
Olof Forshell

1

Ich nehme an, es hängt davon ab, wie Sie "vorzeitig" definieren. Es ist nicht von Natur aus böse, die Funktionalität auf niedriger Ebene beim Schreiben schnell zu machen. Ich denke, das ist ein Missverständnis des Zitats. Manchmal denke ich, dass dieses Zitat mehr Qualifikation verträgt. Ich würde jedoch die Kommentare von m_pGladiator zur Lesbarkeit wiederholen.


1

Die Antwort lautet: es kommt darauf an. Ich werde argumentieren, dass Effizienz für bestimmte Arten von Arbeiten, wie komplexe Datenbankabfragen, eine große Rolle spielt. In vielen anderen Fällen verbringt der Computer die meiste Zeit damit, auf Benutzereingaben zu warten. Daher ist die Optimierung des meisten Codes im besten Fall eine Verschwendung von Aufwand und im schlimmsten Fall kontraproduktiv.

In einigen Fällen können Sie das Design auf Effizienz oder Leistung (wahrgenommen oder real) ausrichten - indem Sie einen geeigneten Algorithmus auswählen oder eine Benutzeroberfläche entwerfen, damit bestimmte kostspielige Vorgänge beispielsweise im Hintergrund ausgeführt werden. In vielen Fällen erhalten Sie durch Profilerstellung oder andere Vorgänge zum Ermitteln von Hotspots einen Vorteil von 10/90.

Ein Beispiel dafür, das ich beschreiben kann, ist das Datenmodell, das ich einmal für ein Gerichtsverwaltungssystem durchgeführt habe, das ungefähr 560 Tabellen enthielt. Es begann normalisiert ("wunderschön normalisiert", wie es der Berater einer bestimmten Big-5-Firma ausdrückte), und wir mussten nur vier denormalisierte Daten darin ablegen:

  • Eine materialisierte Ansicht zur Unterstützung eines Suchbildschirms

  • Eine vom Trigger verwaltete Tabelle zur Unterstützung eines anderen Suchbildschirms, der mit einer materialisierten Ansicht nicht möglich ist.

  • Eine denormalisierte Berichtstabelle (diese gab es nur, weil wir einige Durchsatzberichte erstellen mussten, als ein Data-Warehouse-Projekt gespeichert wurde.)

  • Eine vom Trigger gepflegte Tabelle für eine Schnittstelle, die nach dem neuesten von ziemlich vielen unterschiedlichen Ereignissen innerhalb des Systems suchen musste.

Dies war (zu der Zeit) das größte J2EE-Projekt in Australasien - weit über 100 Jahre Entwicklerzeit - und es enthielt 4 denormalisierte Elemente im Datenbankschema, von denen eines überhaupt nicht dorthin gehörte.


1

Vorzeitige Optimierung ist nicht die Wurzel ALLEN Übels, das ist sicher. Es gibt jedoch Nachteile:

  • Sie investieren mehr Zeit in die Entwicklung
  • Sie investieren mehr Zeit, um es zu testen
  • Sie investieren mehr Zeit in die Behebung von Fehlern, die sonst nicht vorhanden wären

Anstelle einer vorzeitigen Optimierung könnte man frühzeitig Sichtbarkeitstests durchführen, um festzustellen, ob tatsächlich eine bessere Optimierung erforderlich ist.


1

Die meisten Befragten, die sich an "PMO" (das teilweise Anführungszeichen) halten, sagen, dass Optimierungen auf Messungen basieren müssen und dass Messungen erst ganz am Ende durchgeführt werden können.

Es ist auch meine Erfahrung aus der Entwicklung großer Systeme, dass Leistungstests am Ende durchgeführt werden, wenn die Entwicklung kurz vor dem Abschluss steht.

Wenn wir den "Ratschlägen" dieser Leute folgen würden, wären alle Systeme unerträglich langsam. Sie wären ebenfalls teuer, da ihr Hardwarebedarf viel höher ist als ursprünglich vorgesehen.

Ich habe lange empfohlen, Leistungstests in regelmäßigen Abständen während des Entwicklungsprozesses durchzuführen: Es wird sowohl das Vorhandensein von neuem Code (wo zuvor kein Code vorhanden war) als auch der Status des vorhandenen Codes angezeigt.

  • Die Leistung von neu implementiertem Code kann mit der Leistung von vorhandenem, ähnlichem Code verglichen werden. Mit der Zeit wird ein "Gefühl" für die Leistung des neuen Codes geschaffen.
  • Wenn vorhandener Code plötzlich durcheinander gerät, haben Sie Verständnis dafür, dass ihm etwas passiert ist, und können ihn sofort untersuchen, nicht (viel) später, wenn er das gesamte System betrifft.

Eine andere Idee ist es, Software auf der Ebene der Funktionsblöcke zu instrumentieren. Während der Ausführung sammelt das System Informationen zu den Ausführungszeiten der Funktionsblöcke. Wenn ein System-Upgrade durchgeführt wird, kann festgestellt werden, welche Funktionsblöcke wie in der früheren Version ausgeführt wurden und welche sich verschlechtert haben. Auf dem Bildschirm einer Software kann über das Hilfemenü auf die Leistungsdaten zugegriffen werden.

Schauen Sie sich dieses hervorragende Stück an, was PMO bedeuten könnte oder nicht.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.