Wofür „optimieren“ Programmierer heute? [geschlossen]

14

In den "guten alten Tagen", als wir Shareware für Freunde auf Disketten kopierten, verwendeten wir auch einiges an Montage. Es gab eine gängige Praxis der "Mikrooptimierung", bei der Sie die Montagelinien anstarrten und anstarrten, bis Sie eine Möglichkeit gefunden hatten, sie in einer Anweisung weniger auszudrücken. Es gab sogar ein Sprichwort, das mathematisch unmöglich war: „ Sie können immer noch eine Anweisung entfernen. “ Da die Änderung der Laufzeitleistung durch kleine konstante Faktoren für die (meisten) Programmierer heutzutage kein großes Problem darstellt, übertragen Programmierer diese Mikrobefehle. Optimierungsbemühungen woanders?

Mit anderen Worten: Kann eine bewährte Methode in einen extremen Zustand versetzt werden, in dem sie keinen Mehrwert mehr bietet? Und verschwendet stattdessen Zeit?

Zum Beispiel: Verschwenden Programmierer Zeit damit, private Methoden zu generalisieren , die nur von einer Stelle aus aufgerufen werden? Wird Zeit verschwendet, um die Testfalldaten zu reduzieren? Sind Programmierer (immer noch) übermäßig besorgt, Codezeilen zu reduzieren?

Im Folgenden finden Sie zwei gute Beispiele für das, wonach ich suche: (1) Zeit damit verbringen, die richtigen Variablennamen zu finden und sogar alles umzubenennen; und (2) Entfernen auch geringfügiger und schwacher Codeduplizierungen.


Beachten Sie, dass sich dies von der Frage " Wofür optimieren Sie? " Unterscheidet , da ich frage, was andere Programmierer zu maximieren scheinen. Das Stigma dabei sind "Mikro" -Optimierungen und daher keine produktive Nutzung der Zeit.

Macneil
quelle
@Macneil, ich weiß nicht, wofür andere Programmierer Mikrooptimieren, aber ich habe nicht viel Zeit dafür. Meine Mitarbeiter sind auch beschäftigt (nur meine 2 Cent).
Job
@Job: Sie haben noch nie jemanden gesehen, der seine Zeit verschwendet und den Code grundlos geändert hat? Betrachten Sie sich als glücklich. Im Folgenden finden Sie zwei hervorragende Beispiele: Variablennamen und geringfügige Code-Duplikationen.
Macneil
1
Die Frage, wie sie derzeit formuliert ist, ist eine Verbesserung. Ich kann die enge Abstimmung nicht entfernen, aber sie wird in ein paar Tagen veralten. Tatsächlich zieht die Frage einige ziemlich gute Antworten an.
Robert Harvey
1
Übrigens kann jedes bewährte Verfahren so extrem sein, dass es keinen Wert mehr erzeugt.
Robert Harvey

Antworten:

22

Code-Formatierung

Don't     get    me   wrong             ,
code      should be   consistent        & 
readable                                , 
but       some   take it         too far.
JeffO
quelle
Ah ja, die guten alten Variablentypen und Variablennamen benötigen ihre eigenen Spalten in einer Reihe von Variablendeklarationen. Oh! Vergaß die zusätzliche Reihe für die =und die vierte für die Initialisierer!
Macneil
[Verdammt, würde stimmen, aber mein Tageslimit ist erreicht ...]
Macneil
3
Unsere Professoren haben uns gezwungen, den Code für unsere Aufgaben auf diese Weise zu formatieren. Ich habe Jahre gebraucht, um diese Angewohnheit loszuwerden.
Oliver Weiler
Ach je. Bei anderen Antworten habe ich gelacht, aber das tut wirklich weh :-(
Steve314
2
+1 Ich habe einmal mit einer Bibliothek gearbeitet, in der der Entwickler sich geweigert hat, seinen Code konstant zu machen, weil er seinen spaltenformatierten Code
Dean Harding
20

Früher habe ich viel Assembler geschrieben. Es ist nicht nur so, dass die Compiler besser geworden sind, es ist auch so, dass die meiste Hardware jetzt eine Menge Logik hat, die der Ausführung von Code außerhalb der Reihenfolge gewidmet ist. Das eigentliche Kleinstproblem ist die Zeitplanung. Die meisten Computeranweisungen benötigen mehrere Maschinentakte, um ein Ergebnis zu erzielen. Eine Speicherbelastung, die den Cache verfehlt, kann mehrere Hundert dauern. Die Idee war also, andere Anweisungen einzuplanen, um etwas Nützliches zu tun, anstatt auf ein Ergebnis zu warten. Und moderne Maschinen können mehrere Befehle pro Taktperiode ausgeben. Als wir anfingen, HW außer Betrieb zu setzen, stellte ich fest, dass der Versuch, mit Handcodierung eine großartige Leistung zu erzielen, zu einem Becherspiel wurde. Erstens würde die außer Betrieb befindliche HW die Anweisungen nicht in Ihrer sorgfältig ausgearbeiteten Reihenfolge ausführen. Die ausgefallene neue HW-Architektur hat den Nachteil einer unzureichenden Software-Planung so weit verringert, dass der Compiler in der Regel nur wenige Prozent Ihrer Leistung erbrachte. Außerdem fand ich heraus, dass Compiler mittlerweile bekannte, aber komplexitätserzeugende Tricks implementieren, wie z. B. Abrollen, Laden von unten, Software-Pipelining usw. Unter dem Strich muss man wirklich hart arbeiten, einige dieser Tricks überspringen und der Compiler schlägt dich. Verwenden Sie sie alle und die Anzahl der benötigten Assembler-Anweisungen erhöht sich um ein Vielfaches!

Noch wichtiger ist wahrscheinlich, dass es bei den meisten Leistungsproblemen nicht um die Anzahl der Befehlsausgaben geht, sondern darum, die Daten in die CPU zu übertragen. Wie oben erwähnt, beträgt die Speicherlatenz jetzt Hunderte von Zyklen, und die CPU kann mehrere Befehle pro Taktperiode ausführen. Sofern das Programm und insbesondere die Datenstrukturen nicht so ausgelegt sind, dass die Cachetrefferrate bei dem Befehl übermäßig hoch ist, erfolgt eine Mikroabstimmung Level wird keine Auszahlung haben. Genau wie militärische Typen sagen, Amateure reden über Taktik, Profis reden über Logistik. Leistungsprogrammierung ist jetzt mehr als 90% Logistik (bewegte Daten). Und dies ist schwer zu quantifizieren, da die moderne Speicherverwaltung in der Regel mehrere Cache-Ebenen aufweist und virtuelle Speicherseiten von einer als TLB bezeichneten Hardwareeinheit verarbeitet werden. Auch die Ausrichtung von Adressen auf niedriger Ebene wird wichtig, da die tatsächlichen Datenübertragungen nicht in Byte-Einheiten erfolgen. oder sogar 64-Bit-Long-Longs, aber sie kommen in Einheiten von Cache-Zeilen. Dann verfügen die meisten modernen Maschinen über Hardware, die versucht, vorherzusagen, welche Cache-Zeilen in naher Zukunft möglicherweise nicht benötigt werden, und automatische Prefetches ausgibt, um sie in den Cache zu bekommen. Die Realität ist also, dass die Leistungsmodelle bei modernen CPUs so komplex sind, dass sie fast unverständlich sind. Sogar detaillierte Hardware-Simulatoren können niemals mit der exakten Logik der Chips mithalten, so dass eine exakte Abstimmung einfach nicht mehr möglich ist.

Es ist immer noch Platz für eine Handcodierung. Mathematische Bibliotheken (wie die Exp-Funktion) sowie die wichtigeren linearen Algebra-Operationen (wie Matrixmultiplikation) werden in der Regel noch von Experten handcodiert, die für den Hardwareanbieter (z. B. Intel, AMD oder IBM) arbeiten, aber wahrscheinlich nur Ich brauche ein paar erstklassige Assembler-Programmierer pro Megacomputer.

Omega Centauri
quelle
1
Die Handcodierung wird für Personen, die außerhalb der CPU-Anbieter arbeiten, immer schwieriger, da die Aufgabe zunehmend von Insiderwissen und herstellerspezifischen Tools (Compiler und Profiler) abhängt. spiral.net versucht, die CPU-Optimierung zu modellieren und die Suche nach optimalen Lösungen zu automatisieren.
rwong
Viele Computersprachen zwingen Programmierer zu einer sinnlosen Mikrooptimierung, da es mühsam ist, doppelte Genauigkeit für Berechnungen zu verwenden, in die die Ergebnisse gerendert werden float. Aus irgendeinem Grund kann ich nicht verstehen, viele Leute denken, dass dies eine gute Sache ist.
Supercat
10

Manchmal verbringe ich (Zeitverschwendung?) Zeit damit, einen guten Namen für eine Variable oder eine Methode zu wählen, damit sie nicht nur genau beschreibend ist, sondern auch einen guten sprachlichen Stil hat.

Es geht etwas weiter, wenn ich versuche, die gesamten Werke (ein Programm) in den gleichen sprachlichen Stil zu bringen. Manchmal ändert sich meine Meinung und ich überarbeite das Buch. :)

Nein, das dauert so lange. Es ist eher selten. Aber ich mag es, die gute Grammatik in meinen Programmen zu behalten.


quelle
3
Die Benennung ist schwer. Daher sollten Sie einen Namen umgestalten, wenn Sie an einen viel besseren denken. Beachten Sie, dass dies die geistige Anstrengung erfasst und hoffentlich auch das "Warum" auskristallisiert.
1
Dies ist in hohem Maße eine Sache für die linke Gehirnhälfte (die linke Gehirnhälfte ist für die Sprachverarbeitung verantwortlich). Als Programmierer mit dem rechten Gehirn beschäftige ich mich in der Regel weniger mit der Semantik als vielmehr damit, wie alle Teile zusammenpassen.
Jason Baker
7
Die Benennung von Variablen und Methoden ist ein wichtiger Bestandteil der Wartbarkeit. Man sollte Zeit damit verbringen, über Namen nachzudenken, damit es der Person, die den Code verwaltet, in 5 Jahren leichter fällt, damit umzugehen.
GroßmeisterB
@grandmaster: Konnte nicht mehr zustimmen.
Robert Harvey
4
@ Rechtshirn: Bitte Code für die Lef-Tbrainers, damit ich deinen Code auch lesen kann
Juan Mendes
10

Zeitliche Komplexität. Ich verbringe viel zu viel Zeit damit, Dinge für die Leistung im schlimmsten Fall auf einer Skala zu optimieren, die um Größenordnungen größer ist als alles, von dem ich weiß, dass es dem Programm realistisch begegnen wird.

Ich bin einfach zu besessen, um das "aber es könnte diesen großen" Knochen wachsen zu lassen , selbst wenn andere Designentscheidungen dies von einem realistischen Geschehen ausschließen.

Sollte jedoch zu meiner Verteidigung das Unrealistische Realität werden, ist die Optimierung wirklich nicht mehr 'mikro'. Beachten Sie, ich sagte nicht unmöglich , aber unrealistisch .

Natürlich haben die Anforderungen Vorrang.

Tim Post
quelle
1
Ich habe für eine Firma gearbeitet, die deswegen untergegangen ist.
Henry
2
@ Henry - Ich verspreche, es war nicht ich :)
Tim Post
1
@Henry: Sie meinen , sie verschwendete Zeit für Dinge zu optimieren , die wahrscheinlich nie passieren würde, oder sie nicht denken über die Dinge , die wahrscheinlich würde „nie“ passieren ... bis sie tat passieren und es war zu spät?
Dean Harding
2
@Henry: Wenn ein Unternehmen ein hochgradig skalierbares Produkt hat und dennoch sinkt, liegt es am Vertrieb und am Marketing (nicht an Kunden mit hohem Kundenvolumen und unzureichender Preisgestaltung), nicht an der Entwicklung.
rwong
1
Das Unternehmen hat zu viel Zeit damit verbracht, ein System für Millionen von Benutzern zu entwerfen, wenn sie keinen Benutzer hatten. Es muss ein Marketingfehler gewesen sein. Ja, lasst uns Marketing beschuldigen, diese Typen sind Idioten.
Henry
8

Ich glaube, ich habe Wochen damit verbracht, mich mit Java-Ausnahmehandlern zu beschäftigen.

Dies ist eine Menge Arbeit für Code, der zwei- oder dreimal pro Jahr fehlschlägt. Sollte dies eine Warnung oder eine Information sein? Fehler oder tödlich? Ist es wirklich fatal, dass der Prozess in fünf Minuten erneut gestartet wird? Ist es wirklich eine Warnung, wenn sich noch alles im Auslieferungszustand befindet?

Viel Nabelschau und Diskussion über die Art eines E / A-Fehlers. Wenn Sie eine Datei nicht über das Netzwerk lesen können, liegt ein Dateifehler oder ein Netzwerkfehler vor? Und so weiter.

Irgendwann habe ich alle Concat-Zeichenfolgen durch ersetzt, String.formatdamit der jährliche Dateifehler nicht zu zusätzlichen Objekten im Heap führt. Das war eine Verschwendung.

sal
quelle
3
Das ist wichtige Arbeit. Der Preis des Scheiterns = Ihre Fehlermeldung, die auf dem täglichen WTF angezeigt wird.
Steve314
7

Ich befasse mich wahrscheinlich zu sehr mit LOCs. Nicht so viele LOCs selbst, sondern mehr Anweisungen und noch mehr doppelte Anweisungen. Ich bin allergisch gegen Code-Duplikate. Im Allgemeinen liebe ich das Refactoring, aber ich nehme an, dass ungefähr 50% von dem, was ich mache, den Code nicht wesentlich schöner macht.

back2dos
quelle
4
+1 für "Ich bin allergisch gegen doppelten Code". Siehe auch meine Antwort hier: programmers.stackexchange.com/questions/14610/…
Macneil
Wenn ich darüber nachdenke - ich habe dieses Problem mit Schleifen, die sich auf einen Punkt beziehen, den Knuth über goto gemacht hat, und manchmal einen oder zwei Zyklen oder einen doppelten Code handeln müssen, um strukturierten Code zu schreiben. Ich werde eine goto in sehr seltenen Fällen (am häufigsten = generierten Code) verwenden, aber meine Variation dieser Störung ist verschwendet Zeit mich Gedanken und das Hantieren mit einer Schleife endlos versucht , eine triviale Ineffizienz zu beseitigen noch den Code lesbar zu halten.
Steve314
5

Lesen Sie eine Datei Zeile für Zeile, anstatt nur die gesamte Zeile in eine Zeichenfolge einzulesen und die Zeichenfolge in einem Take zu verarbeiten.

Sicher, es macht einen Unterschied in der Ausführungsgeschwindigkeit, ist aber selten die zusätzlichen Codezeilen wert. Es macht den Code weit weniger wartbar und vergrößert den Code.

Ja, das macht wahrscheinlich keinen Sinn, wenn die Datei 3 GB groß ist, aber die meisten Dateien sind nicht so groß (zumindest nicht die, mit denen ich arbeite ;-)).

Oliver Weiler
quelle
3
Selbst wenn es 3 GB oder mehr sind, kann ein 64-Bit-Computer mit virtuellem Speicher umgehen. Verwenden Sie eine Speicherzuordnungsdatei, und es wird nicht einmal ein Teil Ihrer Datei gelesen, bis es benötigt wird. Wohlgemerkt, auch das ist im Normalfall eine Mikrooptimierung.
Steve314
3

Als ich Assemblersprache schrieb, war es sinnvoll, keine Bytes und Zyklen auszuwählen, aber das ist lange her und Compiler haben seitdem einen langen Weg zurückgelegt. Ich würde jetzt nicht versuchen, eine manuell zu optimieren.

Als ich zum Schreiben in C wechselte, war es ziemlich einfach, einen besseren Job als die C-Compiler zu machen, aber jedes Jahr veröffentlichten Borland oder Microsoft oder jemand anderes ein neues und verbessertes, das das vorherige im Raum herumwirbelte. Ich fing an, auf den tatsächlichen Assembler-Code zu achten, den der Compiler ausgibt, und, wenn er keinen netten und engen Code schreibt, Schleifen abwickelt, Variablen außerhalb der Schleifen verschiebt usw.

Heute schreibe ich in viel höheren Sprachen wie Perl, Python und Ruby. Ich benutze einige der Compiler-Tricks, wie das Abrollen von Schleifen, wenn es sinnvoll ist, das Verschieben statischer Variablen außerhalb der Schleifen usw., aber ich mache mir darüber nicht so viele Sorgen, weil CPUs jetzt ein kleines bisschen schneller sind. Wenn sich eine App unerwartet zu bewegen scheint, benutze ich einen Profiler, um zu sehen, was ich finden kann. Wenn sich etwas verbessern lässt, beginne ich mit dem Benchmarking verschiedener Methoden, mit denen ich mir vorstellen kann, etwas schneller zu machen, und sehe dann, wie es funktioniert skaliert.

Im Allgemeinen versuche ich, klug zu sein, wie ich Code schreibe, basierend auf jahrelanger Erfahrung.

der Blechmann
quelle
Hallo Greg, danke für die Antwort, aber ich suche, was Programmierer tun, um Zeit zu verschwenden , nicht um die Laufzeitleistung zu optimieren. Es gibt oben zwei großartige Beispiele: Variablennamen und das Entfernen sogar geringfügiger Codeduplizierungen.
Macneil
3

Eine Mikrooptimierung: Verbesserung der Single-Thread-Leistung von Dingen, die parallelisierbar sind oder die einfach mit neuer Hardware verbessert werden können.

Wenn auf einem Computer vor 10 Jahren etwas langsam ist, ist es wahrscheinlich eine billigere Lösung, einen neueren, schnelleren Computer zu kaufen, anstatt Zeit für die Optimierung des Programmierers zu verschwenden. Ein großer Fokus der Optimierungen sollte jedoch darauf liegen, einen Weg zu finden, die 8 Kerne, die Sie heute bekommen können, oder die 64, die Sie in ein paar Jahren bekommen können, zu verwenden, anstatt sich über Kleinigkeiten wie die zusätzlichen Kosten für Müll zu quälen Sammlung.

Kevin Cantu
quelle
2

Die Mikrooptimierung im Hinblick auf die Laufzeitleistung ist auch heute kaum ein geschlossenes Problem (obwohl dies weniger häufig vorkommt). Ich muss den Leuten gelegentlich erklären, dass der Aufwand für die Zuweisung eines zusätzlichen Objekts für jede Anforderung oder das Hinzufügen eines zusätzlichen Funktionsaufrufs vernachlässigbar ist.

Abgesehen davon sehe ich auch Programmierer, die der Einfachheit halber (einschließlich meiner selbst) Mikrooptimierungen vornehmen. Ich muss noch an einem Ort arbeiten, an dem ich den Unterschied zwischen Einfachheit und Einfachheit nicht erklären musste.

Jason Baker
quelle
Warum sollten Programmierer. anders sein? Was ist der Unterschied, bitte.
Dan Rosenstark
@Yar - Warum sollten sich Programmierer von was unterscheiden?
Jason Baker
warum sollte programmers.= programmers.stackexchange.comanders sein von jedem Ort , dass Sie haben gearbeitet , wo Sie gehabt haben , den Unterschied zwischen diesen beiden Begriffen zu erklären? Bitte erläutern Sie den Unterschied.
Dan Rosenstark
@ Yar - ich weiß nicht, dass es würde. Tatsächlich möchte programers.se Programmierern helfen, Wissen zu bündeln, und ich hoffe, dass es nicht so ist, dass die Leute durch meine Antwort zumindest ein bisschen aufgeklärt werden.
Jason Baker
2
Also, was ist der Unterschied zwischen Einfachheit und Einfachheit?
Dan Rosenstark
2

Ich bin alle für das Prinzip "Nicht optimieren, es sei denn, es ist wirklich notwendig". Und ich bin alle für das Prinzip des ersten Profils. Und im Prinzip werde ich nur etwas optimieren, das den nötigen Unterschied ausmacht.

Das ist im Prinzip so. Aber das Prinzip ist ein Lügner.

Ich habe die Angewohnheit, auf Funktionen in häufig verwendeten Bibliotheken zu achten, von denen ich denke, dass sie in inneren Schleifen häufig verwendet werden. Und wenn Sie dann etwas in einer anderen Funktion entdecken, das nicht so oft verwendet wird ...

Oh - und dann gibt es die Logik "Ich schreibe es - natürlich ist es eine wichtige Bibliothek".

Oh - und übrigens. Ich habe noch nie einen Profiler verwendet, um eine Optimierung durchzuführen. Habe keinen Zugang zu einem kommerziellen und habe nie die Motivation aufgebaut, gprof herauszufinden.

Grundsätzlich bin ich ein Heuchler. Diese Prinzipien gelten für andere Leute, aber ich habe zu viel Angst, dass jemand sagt: "Aber warum hast du es so langsam und beschissen geschrieben?" so kann ich sie nie richtig auf mich selbst anwenden.

Ich bin allerdings nicht so schlimm, wie ich es hier sehe. Und ich bin völlig immun gegen Selbsttäuschung, also weißt du, dass ich damit Recht habe!

BEARBEITEN

Ich sollte hinzufügen - einer meiner größten dummen Probleme ist der Aufwand für Anrufe. Natürlich nicht überall, aber in jenen Fällen, in denen ich denke, dass es sehr oft in inneren Schleifen verwendet wird (in denen ich keine objektiven Beweise für ein Problem habe). Ich habe bösen offsetof-basierten Code geschrieben, um zu vermeiden, dass virtuelle Methodenaufrufe mehrmals ausgeführt werden. Das Ergebnis ist möglicherweise sogar langsamer, da es wahrscheinlich kein Codierungsstil ist, mit dem Optimierer gut umgehen sollen - aber es ist schlauer ;-)

Steve314
quelle
+1 Ah ja! Diese Klasse analysiert die hochspezifischen und eigenwilligen Befehlszeilenargumente meiner Anwendung, lässt mich diese jedoch formatieren und vollständig dokumentieren, wenn Javadoc verwendet wird, da dies sicherlich noch Jahre dauern wird. [Muss später noch angepasst werden, meine tägliche Obergrenze ist erreicht.]
Macneil,
@ Macneil - das ist Doxygen, ich lasse dich wissen. Mit jeder Option, die ich aktiviert finde, wird jede kleine Funktion detailliert "dokumentiert", zusammen mit einem Dutzend hübscher GraphViz-Grafiken. Es hilft wirklich jedem zu verstehen, wie wichtig mein Code ist - und der Ausdruck kann ein ziemlich großes Bürogebäude tapezieren.
Steve314
1

In den alten Zeiten, in denen auf Computern die Uhrzeit in Mikrosekunden, der Speicher in Kilobyte und die primitiven Compiler gemessen wurden, ergab die Mikrooptimierung einen Sinn.

Aufgrund der Geschwindigkeit und Größe der Computer der aktuellen Generation sowie der Qualität der Compiler der aktuellen Generation ist die Mikrooptimierung in der Regel eine reine Zeitverschwendung. Ausnahmen sind in der Regel, wenn Sie aus einem rechenintensiven Code unbedingt die maximale Leistung herausholen müssen ... oder wenn Sie für ein eingebettetes System mit äußerst begrenzten Ressourcen schreiben.

Aber ich suche, was Programmierer tun, um Zeit zu verschwenden und nicht, um die Laufzeitleistung zu optimieren.

Twitter und Facebook fallen mir ein :-)

Stephen C
quelle
Hallo Stephen, das ist ein großartiger Kommentar zur Mikrooptimierung, aber sehen Sie moderne Entsprechungen? [Facebook und Twitter sind keine "Best Practices", die zu weit verbreitet werden können.]
Macneil
Es macht immer noch Sinn. Die Uhrzeiten mögen um Größenordnungen kleiner sein, aber der Code ist um Größenordnungen größer ...
hplbsh
@Stuart - das heißt, es gibt um Größenordnungen mehr Code für die Mikrooptimierung ... der einfach nicht skaliert.
Stephen C