Es scheint, dass Optimierung heutzutage eine verlorene Kunst ist. Gab es nicht eine Zeit, in der alle Programmierer jede Unze Effizienz aus ihrem Code herausgepresst haben? Tun Sie dies oft, während Sie fünf Meilen im Schnee laufen?
Welche Tipps kennen Sie für einfache (oder möglicherweise komplexe) Änderungen zur Optimierung des C # /. NET-Codes, um eine verlorene Kunst zurückzubringen? Da es eine so breite Sache ist, die davon abhängt, was man erreichen will, würde es helfen, den Kontext mit Ihrem Tipp zu versehen. Zum Beispiel:
- Wenn Sie viele Zeichenfolgen miteinander verketten, verwenden Sie
StringBuilder
stattdessen. Siehe Link unten für Vorbehalte dazu. - Verwenden Sie
string.Compare
diese Option , um zwei Zeichenfolgen zu vergleichen, anstatt so etwas zu tunstring1.ToLower() == string2.ToLower()
Der bisherige allgemeine Konsens scheint entscheidend zu sein. Diese Art verfehlt den Punkt: Das Messen sagt Ihnen nicht, was falsch ist oder was Sie dagegen tun müssen, wenn Sie auf einen Engpass stoßen. Ich bin einmal auf den Engpass bei der Verkettung von Zeichenfolgen gestoßen und hatte keine Ahnung, was ich dagegen tun sollte. Daher sind diese Tipps hilfreich.
Mein Punkt, um dies überhaupt zu veröffentlichen, ist es, einen Platz für häufige Engpässe zu haben und wie sie vermieden werden können, bevor sie überhaupt auftreten. Es geht nicht unbedingt um Plug-and-Play-Code, dem jeder blind folgen sollte, sondern vielmehr darum, ein Verständnis dafür zu erlangen, dass über die Leistung zumindest etwas nachgedacht werden sollte und dass einige häufige Fallstricke zu beachten sind.
Ich kann jedoch sehen, dass es nützlich sein kann, auch zu wissen, warum ein Tipp nützlich ist und wo er angewendet werden sollte. Für den StringBuilder
Tipp habe ich die Hilfe gefunden, die ich vor langer Zeit hier auf Jon Skeets Website gemacht habe .
quelle
Antworten:
Es gab einmal am Tag, als die Herstellung von beispielsweise Mikroskopen als Kunst praktiziert wurde. Die optischen Prinzipien wurden schlecht verstanden. Es gab keine Standardisierung von Teilen. Die Röhren, Zahnräder und Linsen mussten von hochqualifizierten Arbeitern von Hand gefertigt werden.
Heutzutage werden Mikroskope als technische Disziplin hergestellt. Die zugrunde liegenden Prinzipien der Physik sind sehr gut verstanden, handelsübliche Teile sind weit verbreitet, und Ingenieure, die Mikroskope bauen, können fundierte Entscheidungen treffen, wie sie ihr Instrument am besten für die Aufgaben optimieren können, für die es entwickelt wurde.
Dass die Leistungsanalyse eine "verlorene Kunst" ist, ist eine sehr, sehr gute Sache. Diese Kunst wurde als Kunst praktiziert . Die Optimierung sollte so angegangen werden, wie sie ist: ein technisches Problem, das durch sorgfältige Anwendung solider technischer Prinzipien gelöst werden kann.
Ich wurde im Laufe der Jahre Dutzende Male nach meiner Liste von "Tipps und Tricks" gefragt, mit denen Leute ihr vbscript / ihr jscript / ihre aktiven Serverseiten / ihren VB / ihren C # -Code optimieren können. Ich widersetze mich immer dem. Das Hervorheben von "Tipps und Tricks" ist genau der falsche Weg, um sich der Leistung zu nähern. Auf diese Weise entsteht Code, der schwer zu verstehen, schwer zu überlegen und schwer zu warten ist und der normalerweise nicht merklich schneller ist als der entsprechende einfache Code.
Der richtige Weg, sich der Leistung zu nähern, besteht darin, sie wie jedes andere Problem als technisches Problem zu betrachten:
Dies ist dasselbe, wie Sie jedes andere technische Problem lösen würden, z. B. das Hinzufügen eines Features - setzen Sie kundenorientierte Ziele für das Feature, verfolgen Sie den Fortschritt bei der Erstellung einer soliden Implementierung, beheben Sie Probleme, wie Sie sie durch sorgfältige Debugging-Analyse finden, und wiederholen Sie sie bis Sie versenden oder scheitern. Leistung ist ein Merkmal.
Die Leistungsanalyse komplexer moderner Systeme erfordert Disziplin und Konzentration auf solide technische Prinzipien, nicht auf eine Tasche voller Tricks, die eng auf triviale oder unrealistische Situationen anwendbar sind. Ich habe noch nie ein reales Leistungsproblem durch Anwendung von Tipps und Tricks gelöst.
quelle
Holen Sie sich einen guten Profiler.
Versuchen Sie nicht einmal, C # (wirklich jeden Code) ohne einen guten Profiler zu optimieren. Es hilft tatsächlich dramatisch, sowohl einen Sampling- als auch einen Tracing-Profiler zur Hand zu haben.
Ohne einen guten Profiler erstellen Sie wahrscheinlich falsche Optimierungen und vor allem Routinen, die überhaupt kein Leistungsproblem darstellen.
Die ersten drei Schritte zur Profilerstellung sollten immer 1) Messen, 2) Messen und dann 3) Messen sein ....
quelle
4) measure
Optimierungsrichtlinien:
Da Prozessoren immer schneller werden, ist der Hauptengpass in den meisten Anwendungen nicht die CPU, sondern die Bandbreite: Bandbreite zum Off-Chip-Speicher, Bandbreite zur Festplatte und Bandbreite zum Netz.
Beginnen Sie am anderen Ende: Verwenden Sie YSlow, um festzustellen, warum Ihre Website für Endbenutzer langsam ist. Gehen Sie dann zurück und korrigieren Sie die Datenbankzugriffe so, dass sie nicht zu breit (Spalten) und nicht zu tief (Zeilen) sind.
In den sehr seltenen Fällen, in denen es sich lohnt, Maßnahmen zur Optimierung der CPU-Auslastung zu ergreifen, achten Sie darauf, dass Sie die Speichernutzung nicht negativ beeinflussen: Ich habe Optimierungen gesehen, bei denen Entwickler versucht haben, die Ergebnisse mithilfe des Speichers zwischenzuspeichern, um CPU-Zyklen zu speichern. Der Nettoeffekt bestand darin, den verfügbaren Speicher auf Cache-Seiten und Datenbankergebnisse zu reduzieren, wodurch die Anwendung weitaus langsamer lief! (Siehe Regel zum Messen.)
Ich habe auch Fälle gesehen, in denen ein "dummer" nicht optimierter Algorithmus einen "cleveren" optimierten Algorithmus geschlagen hat. Unterschätzen Sie niemals, wie gut Compiler-Writer und Chip-Designer darin geworden sind, "ineffizienten" Loop-Code in supereffizienten Code umzuwandeln, der mit Pipelining vollständig im On-Chip-Speicher ausgeführt werden kann. Ihr 'cleverer' baumbasierter Algorithmus mit einer unverpackten inneren Schleife, die rückwärts zählt und von Ihnen als 'effizient' eingestuft wurde, kann einfach deshalb geschlagen werden, weil er während der Ausführung nicht im On-Chip-Speicher verbleibt. (Siehe Regel zum Messen.)
quelle
Beachten Sie bei der Arbeit mit ORMs N + 1 Selects.
List<Order> _orders = _repository.GetOrders(DateTime.Now); foreach(var order in _orders) { Print(order.Customer.Name); }
Wenn die Kunden nicht eifrig geladen werden, kann dies zu mehreren Roundtrips zur Datenbank führen.
quelle
quelle
OK, ich muss meinen Favoriten einwerfen: Wenn die Aufgabe lang genug für die menschliche Interaktion ist, verwenden Sie eine manuelle Unterbrechung im Debugger.
Vs. Als Profiler erhalten Sie einen Aufrufstapel und Variablenwerte, mit denen Sie wirklich verstehen können, was los ist.
Wenn Sie dies 10 bis 20 Mal tun, erhalten Sie eine gute Vorstellung davon, welche Optimierung wirklich einen Unterschied machen kann.
quelle
Wenn Sie eine Methode als Engpass identifizieren, aber nicht wissen, was Sie dagegen tun sollen, stecken Sie im Wesentlichen fest.
Also werde ich ein paar Dinge auflisten. All diese Dinge sind keine Silberkugeln und Sie müssen Ihren Code trotzdem profilieren . Ich mache nur Vorschläge für Dinge, die Sie tun könnten und die manchmal helfen können. Besonders die ersten drei sind wichtig.
quelle
Die Leute haben lustige Ideen darüber, worauf es wirklich ankommt. Der Stapelüberlauf ist voller Fragen, zum Beispiel,
++i
ob er "performanter" ist alsi++
. Hier ist ein Beispiel für eine echte Leistungsoptimierung , und es ist im Grunde das gleiche Verfahren für jede Sprache. Wenn Code einfach auf eine bestimmte Weise geschrieben wird, "weil er schneller ist", ist das eine Vermutung.Sicher, Sie schreiben nicht absichtlich dummen Code, aber wenn das Erraten funktioniert, wären keine Profiler und Profiling-Techniken erforderlich.
quelle
Die Wahrheit ist, dass es keinen perfekt optimierten Code gibt. Sie können jedoch für einen bestimmten Teil des Codes auf einem bekannten System (oder einer Reihe von Systemen) auf einem bekannten CPU-Typ (und einer bekannten Anzahl), einer bekannten Plattform (Microsoft? Mono ?), Einer bekannten Framework- / BCL- Version, optimieren. eine bekannte CLI-Version, eine bekannte Compiler-Version (Fehler, Spezifikationsänderungen, Optimierungen), eine bekannte Menge an Gesamt- und verfügbarem Speicher, ein bekannter Assembly-Ursprung ( GAC ? disk? remote?) mit bekannter Hintergrundsystemaktivität aus anderen Prozessen.
Verwenden Sie in der realen Welt einen Profiler und sehen Sie sich die wichtigen Elemente an. Normalerweise sind die offensichtlichen Dinge alles, was mit E / A zu tun hat, alles, was mit Threading zu tun hat (dies ändert sich wiederum enorm zwischen den Versionen) und alles, was Schleifen und Suchvorgänge beinhaltet, aber Sie könnten überrascht sein, welcher "offensichtlich schlechte" Code eigentlich kein Problem ist. und welcher "offensichtlich gute" Code ist ein großer Schuldiger.
quelle
Sagen Sie dem Compiler, was zu tun ist, nicht wie . Zum Beispiel
foreach (var item in list)
ist besser alsfor (int i = 0; i < list.Count; i++)
undm = list.Max(i => i.value);
ist besser alslist.Sort(i => i.value); m = list[list.Count - 1];
.Indem Sie dem System mitteilen, was Sie tun möchten, können Sie den besten Weg finden, dies zu tun. LINQ ist gut, da die Ergebnisse erst berechnet werden, wenn Sie sie benötigen. Wenn Sie immer nur das erste Ergebnis verwenden, muss es den Rest nicht berechnen.
Letztendlich (und dies gilt für alle Programmierungen) minimieren Sie Schleifen und minimieren Sie, was Sie in Schleifen tun. Noch wichtiger ist es, die Anzahl der Schleifen in Ihren Schleifen zu minimieren. Was ist der Unterschied zwischen einem O (n) -Algorithmus und einem O (n ^ 2) -Algorithmus? Der O (n ^ 2) -Algorithmus hat eine Schleife innerhalb einer Schleife.
quelle
Ich versuche nicht wirklich, meinen Code zu optimieren, aber manchmal werde ich etwas wie Reflektor verwenden, um meine Programme wieder in den Quellcode zu versetzen. Es ist interessant, dann zu vergleichen, was ich falsch mache, mit dem, was der Reflektor ausgibt. Manchmal finde ich, dass das, was ich in einer komplizierteren Form getan habe, vereinfacht wurde. Kann die Dinge nicht optimieren, hilft mir aber, einfachere Lösungen für Probleme zu finden.
quelle