Ich habe viel relativ einfache numerische Programmierung und eine große Menge an Programmierung im Allgemeinen gemacht. In dieser Zeit habe ich festgestellt, dass viele Menschen dazu neigen, das zu tun, was ich Optimierung durch Verdächtigung oder Optimierung durch Hörensagen nenne. Einige von diesen sind wirklich Optimierungen (und tatsächlich, einige von ihnen machen einen signifikanten Unterschied in der tatsächlichen Geschwindigkeit der Ausführung), und einige nicht. Ich versuche, eine Liste von diesen zu kompilieren, mit dem Endziel, sie zu profilieren, um zu sehen, ob sie wirklich einen Unterschied machen mit modernen Compilern und wie viel von ihnen sie machen.
Einige Beispiele könnten sein:
x++
gegen ++x
1/2*a*b*c/(d*e)*x^2)
in einer Schleife berechnen müssen, wobei a, b, c, d, e
innerhalb der Schleife nicht variiert, ist die Vorberechnung des Koeffizienten schneller Der schlechte Name für viele vorzeitige Optimierungen kommt davon, für ein anderes Alter zu sein.
Dann:
Jetzt:
Eine Sache, die man beachten sollte, ist, wenn man vom Desktop zum Embedded wechselt, man erhält einen allgemeinen Technologie-Rückfall von zehn Jahren.
Also hier ist eine Liste von Dingen, die ich entweder meinem Compiler überlasse oder nicht mehr mache
(e.g. x*5 == x+(x<<2))
ersetzen
Vorzeitige Optimierungen sind nicht schlecht. Ansonsten müssten wir alle Bubble-Sortierung verwenden, bis bewiesen ist, dass die Sortierung ein Flaschenhals ist :-) Knuth, in seinem ursprünglichen Zitat, kritisierte die Konzentration auf die kleinen Dinge, anstatt sich mit der Leistung auf einer höheren Ebene zu befassen - Design, Datenzugriffsmuster und Algorithmen.
Frühe Optimierung (oder "Optimierung durch Verdächtigung", wie Sie sagen, ich mag diesen Begriff) ist nur dann böse, wenn es sich als nicht effektiv erweist und den Code (wie Lesbarkeit, Einfachheit oder Flexibilität).
Außerdem erhält der Bibliothekscode etwas Spielraum. Sie wissen nicht, wie oft Ihre neuen UnfuddleString-Funktionen schließlich von Endbenutzeraktionen aufgerufen werden.
Mein Favorit ist es, keine Methodenaufrufe unter den Bedingungen von for-Schleifen zu platzieren.
Beispiel (in einer Sprache mit Schleifen):
%Vor%Ich erinnere mich an die Lektüre des Underhanded Competition für 2006, bei dem es darum ging, einen perfekten Code zu schreiben, der auf verschiedenen Plattformen mit extrem unterschiedlichen Geschwindigkeiten lief. Der Gewinner hatte im Wesentlichen eine For-Schleife mit einem Strlen-Aufruf in der Bedingung geschrieben, was zu einer 100-fachen Geschwindigkeitsverschlechterung unter Windows mit Cygwins GCC (oder ähnlichem) führte. Grundsätzlich, wenn es jedes Mal ausgewertet wird und der Wert sich nicht ändert ... traue dem Compiler nicht, es herauszuziehen; Verschiebe es selbst.
Zwei, die ich gesehen habe:
Es ist schwierig, weil einige offensichtliche Optimierungen nicht ohne Programmierintervention gemacht werden, obwohl die Dinge immer besser werden.
x ++ für benutzerdefinierte Klassen in C ++ ist möglicherweise langsamer. Für Primitive, nicht so sehr.
C ++ Compiler schlagen routinemäßig fehl , um je nach Typ mehrere konstante Additionen, Divisionen usw. zu falten. p>
Die Reihenfolge der mehrdimensionalen Array-Scans wird wichtig, wenn das gesamte Array zu groß ist, um in den L1-Cache zu passen.
Ein sehr häufig:
Eins, das üblich war (aber hoffentlich nicht mehr, da es viele andere Probleme aufwirft und mit OO-Programmierung sinnlos wurde):
Zwei, von denen ich vermute, dass sie das genaue Gegenteil des Ziels erreichen (macht die Compiler-Aufgabe schwieriger und erreicht weniger Optimierung):
Einige benutze ich manchmal (wie ich Beweise in der Vergangenheit hatte Compiler nicht so gut mit manchmal große Leistung Vorteile ... ist es immer noch so?)
Einige alte Klassiker:
while (*x++)
und so) x ++ versus ++ x ist kein Optimierungsproblem, sondern ein Problem mit der Klarheit der Absicht. Möchten Sie den alten Wert von x tatsächlich verwenden? (Hinweis: normalerweise nicht.) Wenn Sie das tun, fahren Sie fort und verwenden Sie x ++, aber geben Sie andernfalls dem Wartungsprogrammierer an, der in zwei Jahren darauf achtet, dass dies nur ein Inkrement ist, nicht mehr.
Genau wie Sie etwas ohne const nicht deklarieren würden, wenn es sich nie semantisch ändern sollte, sollten Sie Ihre Pre / Post-Inkremente verwenden, um Ihre Absicht zu zeigen.
In for-Schleifen deklarieren keine Variablen.
%Vor%Ich habe festgestellt, dass dies in einigen Sprachen besser ist, da es einige Probleme zu reduzieren scheint:
%Vor%Es gibt eine Tendenz, sich auf kleine Dinge zu konzentrieren und darüber zu urteilen, während das große Bild fehlt. Vieles, wie große Software entworfen wird, hat eine implizite Logik der Performance und ist daher meiner Meinung nach eine vorzeitige Optimierung. Beispiele:
Sammlungen mit Hash-Codierung. Hash-Codierung kann O (1) Verhalten (eine Performance-Grundregel) haben, aber für Sammlungen mit vernünftiger Größe kann viel Overkill sein.
Benachrichtigungs-Programmierung. Es ist schwierig, Daten vollständig denormalisiert zu halten, daher müssen Programmierer eine Möglichkeit haben, mit der denormalisierten Struktur (die inkonsistente Zustände aufweist) umzugehen. Die Methode, die normalerweise verwendet wird, hat "Eigenschaften" mit Getter und Setter, die dazu ermutigt werden, Änderungen sofort in der gesamten Datenstruktur zu propagieren, um sie konsistent zu halten. Die Begründung ist, dass dies bessere Leistung im Vergleich zu einer Strategie, eine gewisse Menge an Inkonsistenz zu tolerieren und separat damit umzugehen. Wenn die Leistungsoptimierung durchgeführt wird, zeigt sich, dass diese Versuche, die Konsistenz zu erhalten, dazu führen, dass als Reaktion auf kleine Änderungen große zusätzliche Arbeit geleistet wird.
Zu viele Klassen und zu viele Datenstrukturen. Oft ist das Grundprinzip für eine Klasse und das Erzeugen von Objekten, dass es ein Konzept im Kopf des Programmierers war, wenn die gleiche Information möglicherweise leicht durch eine Art von O (N) -Sweep aus anderen Daten extrahiert werden konnte. Wenn die Leute O (N) denken, denken sie an eine schlechte Leistung (Schrecken). Daher wird die Leistung zu einer impliziten vorzeitigen Rechtfertigung für die zusätzliche Datenstruktur.
Iteratoren. Leute werden ermutigt, Standard-Auflistungsklassen mit Iteratoren zu verwenden, und ihnen wird gesagt, dass der Compiler die Iteratoren optimieren wird (d. H. Sie werden eine gute Leistung haben). Dann, wenn sie in Low-Level-Schleifen verwendet werden, raten Sie was? Durchlaufen Sie den Code auf der Assembly-Ebene und durchlaufen Sie alle Arten von Allgemeinheit, die kein Compiler jemals verstehen könnte. In inneren Schleifen ohne Funktionsaufrufe sind Iteratoren suspekt.
In der Arbeit, die ich im Performance-Tuning gemacht habe, muss ich oft ein Rattennest mit überschüssiger Datenstruktur aus dem Weg räumen, was massive Leistungsprobleme verursacht. Und der häufigste Grund für die überschüssige Datenstruktur ist "Leistung".
Hier ist ein kleines Beispiel.
HINZUGEFÜGT: Es gibt andere Probleme mit falscher Vorhersage, die zu Leistungsproblemen führen können, z. B. übermäßige Globalisierung. Das Extrahieren von Strings aus Ressourcen beim App-Start ist nicht billig.
Einige der häufigsten, die ich finde (einige spezifisch in der .NET-Welt):
Verwendung von kleineren Integer-Typen anstelle von Int32
.
++i
verwendet anstelle von i++
Verwenden von StringBuilder
class, um eine kleine Anzahl von Zeichenfolgen zu erstellen
for
anstelle von foreach
eine allgemeine Abneigung gegen Typ-Validierung und Casting, wie:
%Vor%Craze für O (1) Datenstrukturen und nicht wissen, was O (1) ist. Eine HashTable wirkt sich nachteilig aus, wenn die Eingabe klein ist.
Aversion gegen try-catch
macht Methoden und Variablen basierend auf Leistung und nicht auf Absicht statisch.
Vermeiden Sie geschlossene Variablen
%Vor% Verwenden von char
anstelle von string während der String-Verkettung , wie:
SELECT COUNT(1) FROM table
anstelle von SELECT COUNT(*) FROM table
(Die fettgedruckten sind diejenigen, die "negative" Auswirkungen haben, und kursiv sind das "kann")
Das heißt, Punkt 5 ist etwas, was ich selbst mache (oder nicht, um genau zu sein), ich liebe das as
Optimierung für Referenztypen ..:)
Tags und Links language-agnostic optimization