Grundoperationen CPU-Zeitkosten

7

Ich habe mich gefragt, wie man Schleifen für Systeme mit sehr begrenzten Ressourcen optimieren kann. Sagen wir, wenn wir eine grundlegende for Schleife haben, wie (in javascript geschrieben):

for(var i = someArr.length - 1; i > -1; i--) { someArr[i] }

Ich weiß ehrlich gesagt nicht, ist nicht != billiger als > ?

Ich wäre dankbar für alle Ressourcen, die die Berechnungskosten im Zusammenhang mit grundlegenden Operatoren abdecken, wie oben erwähnt, >> , ~ , ! und so weiter.

    
Kosmotaur 18.08.2009, 20:02
quelle

6 Antworten

15

Leistung auf einer modernen CPU ist alles andere als trivial. Hier sind ein paar Dinge, die es komplizieren:

  • Computer sind schnell. Ihre CPU kann mehr als 6 Milliarden Befehle pro Sekunde ausführen. So kann selbst die langsamste Anweisung millionenfach pro Sekunde ausgeführt werden, was bedeutet, dass es nur wichtig ist , wenn Sie sehr oft verwenden
  • Moderne CPUs haben Hunderte von Befehlen gleichzeitig im Flug. Sie sind pipelined, was bedeutet, dass, während eine Anweisung gelesen wird, eine andere aus Registern liest, eine dritte gerade ausführt und eine vierte in ein Register zurückschreibt. Moderne CPUs haben 15-20 solcher Stufen. Darüber hinaus können sie 3-4 Anweisungen gleichzeitig auf jeder dieser Stufen ausführen. Und sie können diese Anweisungen neu ordnen. Wenn die Multiplikationseinheit von einer anderen Anweisung verwendet wird, können wir vielleicht eine Additionsanweisung finden, die stattdessen ausgeführt wird. Selbst wenn Sie einige langsame Anweisungen eingegeben haben, können Sie die Kosten meistens sehr gut verbergen, indem Sie andere Anweisungen ausführen, während Sie darauf warten, dass der langsame Befehl beendet wird.
  • Der Speicher ist hundertmal langsamer als die CPU. Die Anweisungen, die ausgeführt werden, sind nicht wirklich wichtig, wenn ihre Kosten durch das Abrufen von Daten aus dem Speicher in den Schatten gestellt werden. Und selbst das ist nicht zuverlässig, weil die CPU eigene On-Board-Caches hat, um diese Kosten zu verbergen.

Also lautet die kurze Antwort: "Versuchen Sie nicht, den Compiler zu überlisten". Wenn Sie in der Lage sind, zwischen zwei äquivalenten Ausdrücken zu wählen, ist der Compiler möglicherweise in der Lage, dasselbe zu tun und wählt den effizientesten aus. Die Kosten einer Anweisung variieren in Abhängigkeit von allen oben genannten Faktoren. Welche anderen Befehle gerade ausgeführt werden, welche Daten sich im Cache der CPU befinden, welches genaue CPU-Modell der Code ist, und so weiter. Code, der in einem Fall sehr effizient ist, kann in anderen Fällen sehr ineffizient sein. Der Compiler wird versuchen, die allgemein effizientesten Anweisungen auszuwählen und sie so gut wie möglich zu planen. Wenn Sie nicht mehr als den Compiler darüber wissen, werden Sie wahrscheinlich keinen besseren Job machen können.

Versuchen Sie nicht solche Mikrooptimierungen, außer Sie wirklich wissen, was Sie tun. Wie oben gezeigt, ist Low-Level-Performance ein lächerlich komplexes Thema, und es ist sehr einfach, "Optimierungen" zu schreiben, die zu einem langsameren Code führen. Oder die einfach die Lesbarkeit auf etwas opfern, das überhaupt keinen Unterschied macht.

Außerdem hat der Großteil Ihres Codes keinen messbaren Einfluss auf die Leistung. Die Leute lieben es, Knuth zu diesem Thema zu zitieren (oder falsch zu zitieren):

  

Wir sollten kleine Wirkungsgrade vergessen, sagen wir etwa 97% der Zeit: vorzeitige Optimierung ist die Wurzel allen Übels

Menschen interpretieren das oft als "Mach dir keine Mühe, deinen Code zu optimieren". Wenn Sie tatsächlich das vollständige Zitat lesen, sollten einige viel interessantere Konsequenzen klar werden:

Die meiste Zeit sollten wir Mikrooptimierungen vergessen. Der meiste Code wird so selten ausgeführt, dass Optimierungen keine Rolle spielen. Unter Berücksichtigung der Anzahl der Anweisungen, die eine CPU pro Sekunde ausführen kann, ist es offensichtlich, dass ein Codeblock oft sehr ausgeführt werden muss, damit Optimierungen ihn beeinflussen. In ungefähr 97% der Fälle werden Ihre Optimierungen Zeitverschwendung sein. Aber er sagt auch, dass manchmal (3% der Zeit), Ihre Optimierungen wichtig sind . Und offensichtlich ist es ein bisschen wie nach einer Nadel im Heuhaufen zu suchen, wenn man nach diesen 3% sucht. Wenn Sie sich im Allgemeinen dafür entscheiden, Ihren Code zu optimieren, werden Sie Ihre Zeit mit den ersten 97% verschwenden. Stattdessen müssen Sie zuerst die 3% ermitteln, die tatsächlich optimiert werden müssen. Mit anderen Worten, führen Sie Ihren Code durch einen Profiler, und lassen Sie es Ihnen sagen, welcher Code die meiste CPU-Zeit beansprucht. Dann weißt du, wo du optimieren musst. Und dann sind deine Optimierungen nicht mehr voreilig.

    
jalf 18.08.2009, 20:44
quelle
9

Es ist außerordentlich unwahrscheinlich, dass solche Mikrooptimierungen einen merklichen Unterschied in Ihrem Code machen, außer in den extremsten (Echtzeit eingebetteten Systemen?) Umständen. Ihre Zeit wäre wahrscheinlich besser, wenn Sie sich darum sorgen, Ihren Code lesbar und wartbar zu machen.

Beginnen Sie im Zweifelsfall immer mit der Frage nach Donald Knuth:

Ссылка

Oder, für eine etwas weniger anspruchsvolle Aufgabe der Mikrooptimierung:

Ссылка

    
Matthew Nizol 18.08.2009 20:21
quelle
1

Die meisten Comparations haben denselben "coast", weil der Prozessor sie einfach in allen Aspekten vergleicht, und danach eine Entscheidung aufgrund von Flags, die durch diese vorherige Komparation erzeugt wurden, annimmt, so dass das Vergleichssignal überhaupt keine Rolle spielt. Aber einige Architekturen versuchen diesen Prozess zu beschleunigen, basierend auf dem Wert, mit dem Sie vergleichen, wie Vergleiche mit 0.

Soweit ich weiß, sind bitweise Operationen die billigsten Operationen, etwas schneller als Addition und Subtraktion. Multiplikations- und Divisionsoperationen sind ein wenig teurer, und die Vergleichbarkeit ist die höchste Küstenoperation.

    
Havenard 18.08.2009 20:20
quelle
1

Das ist wie nach einem Fisch zu fragen, wenn ich Ihnen lieber beibringen möchte zu fischen.

Es gibt einfache Möglichkeiten, selbst zu sehen, wie lange die Dinge dauern. Am liebsten kopiere ich den Code 10 Mal und wickle ihn dann in eine 10 x 8-Schleife. Wenn ich es starte und auf meine Uhr schaue, wird die Anzahl der Sekunden in Nanosekunden umgewandelt.

Sprich keine vorzeitige Optimierung ist ein "nicht sein". Wenn Sie ein "do be" möchten, können Sie eine proaktive Performance-Tuning-Technik ausprobieren, zB das .

Übrigens ist meine Lieblingsmethode zum Codieren Ihrer Schleife:

%Vor%     
Mike Dunlavey 19.08.2009 00:43
quelle
0

Vorzeitige Optimierung kann gefährlich sein. Der beste Ansatz wäre, Ihre Anwendung zu schreiben, ohne sich darum zu kümmern, und dann die langsamen Punkte zu finden und diese zu optimieren. Wenn Sie sich darüber Sorgen machen, verwenden Sie eine niedrigere Sprache. Eine interpretierte Sprache wie JavaScript kostet im Vergleich zu einer niedrigeren Programmiersprache wie C etwas Rechenleistung.

    
RHicke 18.08.2009 20:23
quelle
0

In diesem speziellen Fall & & gt; vs = ist wahrscheinlich kein Leistungsproblem. JEDOCH & gt; ist in der Regel sicherer Wahl weil verhindert Fälle, in denen Sie den Code in die Unkräuter und in einer Endlosschleife stecken abgeändert.

    
NoMoreZealots 18.08.2009 21:33
quelle

Tags und Links