Wann ist Optimierung nicht verfrüht und daher nicht böse?


75

"Vorzeitige Optimierung ist die Wurzel allen Übels" haben fast alle von uns gehört / gelesen. Ich bin gespannt, welche Art von Optimierung nicht verfrüht ist, dh in jeder Phase der Softwareentwicklung (High-Level-Design, Detail-Design, High-Level-Implementierung, Detail-Implementierung usw.), welchen Grad an Optimierung wir in Betracht ziehen können, ohne dass dies auf die dunkle Seite übergeht.



Antworten:


116

Wenn Sie sich auf Erfahrung stützen? Nicht böse "Jedes Mal, wenn wir X gemacht haben, haben wir einen brutalen Leistungseinbruch erlitten. Lassen Sie uns dieses Mal entweder X optimieren oder ganz vermeiden."

Wann ist es relativ schmerzfrei? Nicht böse "Das als Foo oder Bar umzusetzen, wird genauso viel Arbeit kosten, aber theoretisch sollte Bar viel effizienter sein. Lassen Sie es uns blockieren."

Wenn Sie beschissene Algorithmen vermeiden, die sich schrecklich skalieren lassen? Nicht böse "Unser technischer Leiter sagt, dass unser vorgeschlagener Algorithmus zur Pfadauswahl in Fakultätszeit abläuft. Ich bin mir nicht sicher, was das bedeutet, aber sie schlägt vor, dass wir Seppuku begehen, um überhaupt darüber nachzudenken. Lassen Sie uns etwas anderes überlegen."

Das Böse entsteht, wenn Sie viel Zeit und Energie aufwenden, um Probleme zu lösen, von denen Sie nicht wissen, dass sie tatsächlich existieren. Wenn die Probleme definitiv existieren oder wenn die Phantom-Psudo-Probleme billig gelöst werden können, verschwindet das Böse.


Steve314 und Matthieu M. heben Punkte in den Kommentaren hervor, die berücksichtigt werden sollten. Grundsätzlich lohnen sich einige "schmerzlose" Optimierungen auch nicht, da die von ihnen angebotene einfache Leistungssteigerung nicht die Verschleierung des Codes wert ist. Sie duplizieren Verbesserungen, die der Compiler bereits durchführt, oder beides. In den Kommentaren finden Sie einige nette Beispiele für allzu kluge Nichtverbesserungen.


22
Gelegentlich ist das einfache Lösen eines Phantomproblems immer noch leicht böse, da es schwieriger ist, Code zu lesen und zu warten. Nicht viel schwieriger (oder es wäre keine einfache Lösung), aber vielleicht gelegentlich immer noch relevant. Ein Beispiel könnte ein cleverer bitweiser Trick sein, den manche Leute nicht erkennen und den der Compiler wahrscheinlich trotzdem anwenden wird, wenn er nützlich ist.
Steve314

26
Ich stimme Steve hier zu, manchmal ist die "Optimierung" einfach nicht wert, besonders weil Compiler so verdammt gut sind. Beispiel? Wenn ies nicht signiert ist, i / 2kann es durch ersetzt werden i >> 1. Es ist schneller. Aber es ist auch kryptischer (nicht jeder wird den Effekt bemerken, auch diejenigen, die Zeit verlieren). Aber das Schlimmste ist, dass der Compiler es trotzdem macht. Warum also den Quellcode verschleiern?
Matthieu M.

19
@ Larry: Hab ich nicht, also denke ich ist es ein gutes Beispiel.
Joris Meys

18
Meiner Ansicht nach sollten Optimierungen, auch wenn sie einfach sind, auch dann als schlecht angesehen werden, wenn sie die Lesbarkeit / Wartbarkeit des Codes beeinträchtigen und nicht auf tatsächlichen Leistungsmessungen beruhen.
Bart van Ingen Schenau

14
@Matthew: Was lehren sie? Schmutzige und unnötige Tricks? Warum? Wenn die Profilerstellung zeigt, dass a i/2in der Tat ein Hot Spot ist und dieser (unglaublich, aber nehmen wir an) i>>1ihn schneller macht, tun Sie es und kommentieren Sie, dass diese Profilerstellung gezeigt hat, dass dies schneller ist. Wenn dies tatsächlich irgendwo benötigt wird (was ich bezweifle, da Compiler, wie Matthieu sagte, klug genug sein sollten, dies selbst zu tun), werden Anfänger etwas lernen, wenn dies nicht der Fall ist (was wahrscheinlich ist), warum möchten Sie einstecken ihre Köpfe mit unnötiger Folklore?
sbi

38

Der Anwendungscode sollte nur so gut wie nötig sein, der Bibliothekscode sollte jedoch so gut wie möglich sein, da Sie nie wissen, wie Ihre Bibliothek verwendet wird. Wenn Sie also Bibliothekscode schreiben, muss dieser in jeder Hinsicht gut sein, sei es in Bezug auf Leistung, Robustheit oder eine andere Kategorie.

Außerdem müssen Sie beim Entwerfen Ihrer Anwendung und beim Auswählen von Algorithmen über die Leistung nachdenken . Wenn es nicht als performant ausgelegt ist, kann es durch keinen Grad an Hackerleistung nachträglich performant gemacht werden und keine Mikrooptimierungen überwiegen einen überlegenen Algorithmus.


5
Der Bibliothekscode sollte dokumentieren, ob er versucht, "so gut wie möglich" zu sein, oder was sein Ziel ist. Code muss nicht unbedingt optimal sein, um nützlich zu sein, vorausgesetzt, der Verbraucher verwendet ihn nur, wenn dies angemessen ist.
Supercat

1
Tut mir leid, aber "in allen Aspekten gut sein" klingt verdächtig nach Überentwicklung. Außerdem ist es wahrscheinlich nicht realistisch - im Leben geht es immer um Kompromisse.
sleske

1
+1 zur Hervorhebung der Entwurfsphase; Wenn Sie die Vorteile absichtlich abwägen, ist dies nicht verfrüht.
Nathan Tuggy

Wenn Sie jedoch nie wissen, wie Ihre Bibliothek verwendet wird, wissen Sie nicht, ob es überhaupt einen geschäftlichen Wert hat, Zeit für die Verbesserung zu investieren. Das ist also kaum ein Argument.
RemcoGerlich

25

Welche Art von Optimierung ist nicht verfrüht?

Die Art, die aufgrund bekannter Probleme auftritt.


17

Wann ist Optimierung nicht verfrüht und daher nicht böse?

Es ist schwer zu sagen, was gut und was böse ist. Wer hat das Recht? Wenn wir uns die Natur ansehen, scheinen wir auf das Überleben programmiert zu sein, mit einer umfassenden Definition von "Überleben", die die Weitergabe unserer Gene an die Nachkommen einschließt.

Zumindest nach unseren Grundfunktionen und unserer Programmierung würde ich sagen, dass Optimierung nicht schlecht ist, wenn sie sich am Ziel der Reproduktion ausrichtet. Für die Jungs gibt es die Blondinen, Brünetten, Rothaarigen, viele schöne. Für Mädchen gibt es Männer, und einige von ihnen scheinen in Ordnung zu sein.

Vielleicht sollten wir auf diesen Zweck hin optimieren, und dort hilft es, einen Profiler zu verwenden. Mit dem Profiler können Sie Ihre Optimierungen und Zeit effektiver priorisieren und erhalten detaillierte Informationen zu Hotspots und deren Ursachen. Dies gibt Ihnen mehr Freizeit für die Fortpflanzung und ihr Streben.


3
Es ist erfrischend, jemanden zu sehen, der dieser alten Kastanie eine frische Note verleiht. Alles was es braucht ist, Knuths gesamtes Zitat zu lesen und nicht nur einen Satz, was?
Robert Harvey

1
@RobertHarvey Ich habe da ein bisschen Ärger mit Haustieren - da so viele nur diesen einen Satz zu zitieren scheinen und so viele wichtige kontextbezogene Informationen dabei verloren gehen. Ich bin mir nicht sicher, ob es eine so gute Antwort ist, da ich eine gewisse Garantie habe. :-D

14

Das vollständige Zitat definiert, wann die Optimierung nicht verfrüht ist:

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 . [Hervorhebung von mir]

Sie können kritischen Code auf viele Arten identifizieren: Kritische Datenstrukturen oder Algorithmen (z. B. stark genutzt oder der "Kern" des Projekts) können wichtige Optimierungen liefern, viele kleinere Optimierungen werden durch Profiler identifiziert und so weiter.


6
Ja ... Es ist gut und schön, 90% der Zeit zu sparen, die ein zufälliger Funktionsaufruf in Anspruch nimmt, aber vielleicht erzielen Sie eine größere Wirkung, wenn Sie sich den Code ansehen, in dem Ihre App tatsächlich 80% ihrer Zeit verbringt, und a dort einige Prozent.

11

Sie sollten auf der Grundlage Ihrer Erfahrungen in jedem Fall eine "ausreichend gute" Lösung wählen.

Der Optimierungsspruch bezieht sich auf das Schreiben von "komplexerem Code als" gut genug ", um ihn schneller zu machen", bevor man tatsächlich weiß, dass er notwendig ist, wodurch der Code komplexer als nötig wird. Komplexität ist das, was die Dinge schwer macht, also ist das keine gute Sache.

Dies bedeutet, dass Sie keine überkomplexe Sortierroutine wählen sollten, die 100-GB-Dateien durch transparentes Wechseln auf die Festplatte sortieren kann, wenn eine einfache Sortierung durchgeführt wird. Sie sollten jedoch auch eine gute Wahl für die einfache Sortierung treffen. Blinde Auswahl von "Blasensortierung" oder "Wähle alle Einträge nach dem Zufallsprinzip aus und überprüfe, ob sie in der richtigen Reihenfolge sind. Wiederholen". ist selten gut.


3

Meine allgemeine Faustregel: Wenn Sie nicht sicher sind, ob Sie die Optimierung benötigen, gehen Sie davon aus, dass Sie dies nicht tun. Denken Sie jedoch daran, wann Sie optimieren müssen. Es gibt jedoch einige Probleme, über die Sie im Vorfeld Bescheid wissen können. Dies beinhaltet normalerweise die Auswahl guter Algorithmen und Datenstrukturen. Wenn Sie beispielsweise die Mitgliedschaft in einer Sammlung überprüfen müssen, können Sie ziemlich sicher sein, dass Sie eine bestimmte Datenstruktur benötigen.


3

Nach meiner Erfahrung liegt die Antwort in der detaillierten Implementierungsphase in der Profilerstellung des Codes. Es ist wichtig zu wissen, was schneller sein muss und was akzeptabel schnell ist.

Es ist auch wichtig zu wissen, wo genau sich der Leistungsengpass befindet - die Optimierung eines Teils des Codes, der nur 5% der Gesamtlaufzeit benötigt, nützt nichts.

Die Schritte 2 und 3 beschreiben eine nicht vorzeitige Optimierung:

  1. Bring es zum Laufen
  2. Prüfung. Nicht schnell genug? Profiliere es .
  3. Optimieren Sie mit den Daten aus Schritt 2 die langsamsten Abschnitte des Codes.

Sie haben Schritt 0 vergessen. Das heißt, Sie müssen die Anwendung ordnungsgemäß erstellen, damit Sie von Anfang an eine angemessene Leistung erwarten können.
Robert Harvey

Ich habe nur über die detaillierte Implementierungsphase gesprochen.
Gorgi Kosev

1
Ich frage Schritt 3 - sehr oft ist die beste Antwort, einen anderen Ansatz zu finden, damit Sie nicht erst den langsamen Code ausführen.
Loren Pechtel

1
Wählen Sie die richtigen Datenstrukturen.
Jasonk

3

Es ist keine Optimierung, wenn Sie Dinge auswählen, die sich nur schwer ändern lassen, z. B .: Hardware-Plattform.

Die Auswahl von Datenstrukturen ist ein gutes Beispiel - entscheidend, um sowohl funktionale als auch nicht funktionale (Leistungs-) Anforderungen zu erfüllen. Nicht leicht zu ändern und doch wird es alles andere in Ihrer App fahren. Ihre Datenstrukturen ändern die verfügbaren Algorithmen usw.


3

Ich kenne nur einen Weg, um diese Frage zu beantworten, nämlich Erfahrung in der Leistungsoptimierung zu sammeln. Das bedeutet: Schreiben Sie Programme, und suchen Sie nach dem Schreiben nach Beschleunigungen, und wiederholen Sie diese. Hier ist ein Beispiel.

Hier ist der Fehler, den die meisten Leute machen: Sie versuchen, das Programm zu optimieren, bevor sie es tatsächlich ausführen. Wenn sie einen Programmierkurs besucht haben (von einem Professor, der nicht viel praktische Erfahrung hat), werden sie eine Brille in O-Farben haben und sie werden denken, darum geht es . Es ist alles das gleiche Problem, vorherige Optimierung. **

Jemand sagte: Mach es erst richtig, dann mach es schnell. Sie hatten Recht.

Aber jetzt zum Kicker: Wenn Sie dies einige Male getan haben, erkennen Sie die dummen Dinge, die Sie zuvor getan haben und die Geschwindigkeitsprobleme verursachen, und vermeiden sie instinktiv. (Dinge wie die Überlastung Ihrer Klassenstruktur, das Überfüllen mit Benachrichtigungen, das Verwechseln der Größe von Funktionsaufrufen mit ihren Zeitkosten, die Liste geht weiter und weiter ...) Sie vermeiden diese instinktiv, aber raten Sie mal, wie es für die Geringeren aussieht. erlebt: vorzeitige optimierung!

Also diese albernen Debatten gehen weiter und weiter :)

** Eine andere Sache, die sie sagen, ist, dass Sie sich keine Sorgen mehr machen müssen, weil Compiler so gut sind und Maschinen heutzutage so schnell sind. (KIWI - Kill It With Iron.) Es gibt keine exponentiellen Hardware- oder Systembeschleunigungen (durchgeführt von sehr intelligenten, hart arbeitenden Ingenieuren), die möglicherweise exponentielle Software-Verlangsamungen (durchgeführt von Programmierern, die so denken) ausgleichen könnten.


2

Wenn es die Anforderungen oder der Markt speziell verlangen.

Beispielsweise ist die Leistung in den meisten Finanzanwendungen eine Anforderung, da eine geringe Latenz von entscheidender Bedeutung ist. Abhängig von der Art des gehandelten Instruments kann die Optimierung von der Verwendung nicht sperrender Algorithmen in einer Hochsprache über die Verwendung einer Niedrigsprache bis hin zum Extrem gehen - Implementierung der Algorithmen zur Ordnungsanpassung in Hardware selbst (z. B. mit FPGA) ).

Ein anderes Beispiel wären einige Arten eingebetteter Geräte. Nehmen Sie zum Beispiel die ABS-Bremse; Erstens gibt es die Sicherheit, wenn Sie die Pause schlagen, sollte das Auto langsamer werden. Aber es gibt auch Leistung, Sie möchten keine Verzögerungen, wenn Sie die Pause treffen.


0

Die meisten Leute würden die Optimierung als verfrüht bezeichnen, wenn Sie etwas optimieren, das aufgrund der Leistung nicht zu einem "Soft Failure" (es funktioniert, aber es ist immer noch nutzlos) des Systems führt.

Beispiele aus der Praxis.

  • Wenn die Ausführung meiner Blasensortierung 20 ms dauert, wird die Optimierung auf 1 ms Quicksort den Gesamtnutzen trotz einer Leistungssteigerung von 2000% nicht in nennenswerter Weise verbessern.

  • Wenn das Laden einer Webseite 20 Sekunden dauert und wir sie auf 1 Sekunde verringern, kann dies den Nutzen der Website von 0 auf nahezu unendlich erhöhen. Grundsätzlich ist etwas, das kaputt war, weil es zu langsam war, jetzt nützlich.


Es ist wichtig zu beachten, dass die Optimierung von 20 ms auf 1 ms eine große Sache ist, wenn Ihre Sortierung im Verlauf Ihres Programms 1000-mal aufgerufen wird.
Beefster

0

Welche Art von Optimierung ist nicht verfrüht?

Eine Optimierung, die ein bekanntes Leistungsproblem mit Ihrer Anwendung behebt, oder eine Optimierung, die es Ihrer Anwendung ermöglicht, gut definierte Akzeptanzkriterien zu erfüllen.

Nachdem die Lösung ermittelt wurde, sollte einige Zeit in Anspruch genommen und der Leistungsvorteil gemessen werden.

(dh es ist nicht - "Ich denke, dieses Teil des Codes scheint langsam zu sein, ich werde X ändern, um stattdessen Y zu verwenden, und das wird schneller sein").

Ich habe viel vorzeitige "Optimierung" erlebt, die den Code letztendlich langsamer gemacht hat - in diesem Fall meine ich "nicht durchdacht". Die Leistung sollte vor und nach der Optimierung verglichen werden, und nur Code, der die Leistung tatsächlich verbessert, sollte beibehalten werden.


0

"Vorzeitige Optimierung ist die Wurzel allen Übels" haben fast alle von uns gehört / gelesen

Wahr. Leider ist es auch eines der am häufigsten (in böswilliger Absicht) missbrauchten Programmierzitate aller Zeiten. Seit Donald Knuth das Mem geprägt hat, lohnt es sich, einen originellen Kontext aus dem Zitat hinzuzufügen:

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 ... sollte sich den kritischen Code genau ansehen. aber erst nachdem dieser Code identifiziert wurde. ... die universelle Erfahrung von Programmierern, die Messwerkzeuge verwendet haben, war, dass ihre intuitiven Vermutungen fehlschlagen

Beachten Sie, dass Knuth speziell über die Ausführungsgeschwindigkeit in der Laufzeit sprach .

..Programmierer verschwenden enorm viel Zeit damit, über die Geschwindigkeit unkritischer Teile ihrer Programme nachzudenken oder sich Gedanken zu machen ..

Außerdem schrieb er den Artikel 1974, als alle Maschinenressourcen, bei denen eine hohe und negative Korrelation zwischen Ausführungsgeschwindigkeit und Wartbarkeit des Programms (höhere Geschwindigkeit - weniger wartbar) bestand, wahrscheinlich stärker waren als jetzt.

OK, um Ihre Frage zu beantworten, laut Donald Knuth ist die Optimierung NICHT verfrüht, wenn sie einen schwerwiegenden Leistungsengpass behebt, der identifiziert wurde (idealerweise gemessen und während der Profilerstellung genau bestimmt ).

Wie ich bereits sagte, ist "vorzeitige Optimierung" eines der am häufigsten missbrauchten Memes. Daher wird die Antwort nicht vollständig sein, ohne einige Beispiele von Dingen, die keine vorzeitigen Optimierungen sind, sondern manchmal als solche abgeschüttelt werden:

  • Engpässe, die mit bloßem Auge sichtbar sind und vermieden werden können, bevor sie eingeführt werden, wie z

Weitere Aspekte beziehen sich nicht einmal auf die Ausführungsgeschwindigkeit:

  • durchdachtes Upfront-Design

  • statische Eingabe (!)

  • usw. / jede Form von geistiger Anstrengung

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.