Ich habe das schon einige Male gehört. Sind JavaScript-Schleifen beim Rückwärtszählen wirklich schneller? Wenn ja warum? Ich habe einige Beispiele für Testsuiten gesehen, die zeigen, dass umgekehrte Schleifen schneller sind, aber ich kann keine Erklärung dafür finden, warum!
Ich gehe davon aus, dass die Schleife nicht mehr jedes Mal eine Eigenschaft auswerten muss, wenn sie prüft, ob sie fertig ist, und sie prüft nur den endgültigen numerischen Wert.
Dh
for (var i = count - 1; i >= 0; i--)
{
// count is only evaluated once and then the comparison is always on 0.
}
for
ist schneller, da die Steuervariable für die obere (hehe, untere) Schleife nicht definiert oder von einem Objekt abgerufen werden muss. es ist eine konstante Null.Antworten:
Es ist nicht
i--
so schnell wiei++
. Eigentlich sind beide gleich schnell.Was in aufsteigenden Schleifen Zeit braucht, ist die Bewertung
i
der Größe Ihres Arrays für jede Schleife . In dieser Schleife:Sie werten
.length
nur einmal aus, wenn Sie deklariereni
, während für diese SchleifeSie bewerten
.length
jedes Mali
, wenn Sie inkrementieren , wenn Sie prüfen, obi <= array.length
.In den meisten Fällen sollten Sie sich nicht einmal um diese Art der Optimierung kümmern .
quelle
.length
eine bestimmte Anzahl von Malen auszuwerten oder eine neue Variable zu deklarieren und zu definieren? In den meisten Fällen handelt es sich um eine vorzeitige (und falsche) Optimierung, es sei dennlength
, die Bewertung ist sehr teuer.0
ist schneller zu bewerten alsarray.length
. Nun, angeblich..length
deklariert werdenfor loop
oder nicht.Dieser Typ hat viele Schleifen in Javascript in vielen Browsern verglichen. Er hat auch eine Testsuite damit Sie sie selbst ausführen können.
In allen Fällen (es sei denn, ich habe eine beim Lesen verpasst) war die schnellste Schleife:
quelle
--i
dann müssen Sievar current = arr[i-1];
innerhalb der Schleife verwenden, oder es wird um eins ausgeschaltet ...Ich versuche mit dieser Antwort ein breites Bild zu vermitteln.
Die folgenden Gedanken in Klammern waren meine Überzeugung, bis ich das Problem erst kürzlich getestet habe:
[[In Bezug auf Low-Level-Sprachen wie C / C ++ wird der Code so kompiliert, dass der Prozessor einen speziellen bedingten Sprungbefehl hat, wenn eine Variable Null (oder nicht Null) ist.
Wenn Sie sich für so viel Optimierung interessieren, können Sie
++i
stattdessen auch geheni++
, da dies++i
ein einzelner Prozessorbefehl ist, währendi++
bedeutetj=i+1, i=j
.]]Wirklich schnelle Schleifen können durch Abrollen erstellt werden:
Es kann viel langsamer sein als
Die Gründe hierfür können jedoch recht kompliziert sein (nur um zu erwähnen, dass es im Spiel Probleme mit der Vorverarbeitung von Prozessorbefehlen und der Cache-Behandlung gibt).
In Bezug auf Hochsprachen wie JavaScript können Sie die Dinge optimieren, wenn Sie sich auf Bibliotheken und integrierte Funktionen für Schleifen verlassen. Lassen Sie sie entscheiden, wie es am besten gemacht wird.
Folglich würde ich in JavaScript vorschlagen, so etwas wie zu verwenden
Es ist auch weniger fehleranfällig und Browser haben die Möglichkeit, Ihren Code zu optimieren.
[BEMERKUNG: Nicht nur die Browser, sondern auch Sie haben einen Platz zum einfachen Optimieren. Definieren Sie die
forEach
Funktion einfach neu (browserabhängig), damit die neuesten Tricks verwendet werden! :) @AMK sagt in besonderen Fällen, dass es sich lohnt, lieberarray.pop
oder zu verwendenarray.shift
. Wenn Sie das tun, stellen Sie es hinter den Vorhang. Der größte Overkill besteht darin, OptionenforEach
zur Auswahl des Schleifenalgorithmus hinzuzufügen .]Darüber hinaus empfiehlt es sich, auch für einfache Sprachen, eine intelligente Bibliotheksfunktion für komplexe Schleifenoperationen zu verwenden, wenn dies möglich ist.
Diese Bibliotheken können auch Dinge (Multithreading) hinter Ihren Rücken legen, und auch spezialisierte Programmierer halten sie auf dem neuesten Stand.
Ich habe etwas genauer nachgesehen und es stellt sich heraus, dass es in C / C ++ selbst bei 5e9 = (50.000x100.000) Operationen keinen Unterschied zwischen Auf und Ab gibt, wenn die Tests gegen eine Konstante durchgeführt werden, wie @alestanis sagt. (JsPerf-Ergebnisse sind manchmal inkonsistent, sagen aber im Großen und Ganzen dasselbe: Sie können keinen großen Unterschied machen.)
Das
--i
ist also eher eine "noble" Sache. Sie sehen nur wie ein besserer Programmierer aus. :) :)Andererseits hat mich das Abrollen in dieser 5e9-Situation von 12 Sekunden auf 2,5 Sekunden, wenn ich um 10 Sekunden ging, und auf 2,1 Sekunden, wenn ich um 20 Sekunden ging, gesenkt. Es war ohne Optimierung, und die Optimierung hat die Dinge auf unermessliche Zeit reduziert. :) (Das Abrollen kann auf meine oben beschriebene Weise oder mithilfe von erfolgen
i++
, aber das bringt in JavaScript keine Fortschritte .)Alles in allem: Behalten Sie
i--
/i++
und++i
/ oderi++
Unterschiede zu den Vorstellungsgesprächen bei, halten Sie sich anarray.forEach
oder andere komplexe Bibliotheksfunktionen, sofern verfügbar. ;)quelle
array.each(...)
. Ich glaube nicht, dass sie versuchen würden, mit einfachen For-Loops zu experimentieren.+1
um dir einGreat Answer
Abzeichen zu besorgen . Wirklich tolle Antwort. :)i--
ist so schnell wiei++
Dieser Code ist genauso schnell wie Ihr Code, verwendet jedoch eine zusätzliche Variable:
Es wird empfohlen, die Größe des Arrays NICHT jedes Mal zu bewerten. Bei großen Arrays kann man den Leistungsabfall sehen.
quelle
for (var i=0, up=Things.length; i<up; i++) {}
Da Sie sich für das Thema interessieren, werfen Sie einen Blick auf Greg Reimers Weblog-Beitrag über einen JavaScript-Loop-Benchmark. Was ist der schnellste Weg, um eine Loop in JavaScript zu codieren? ::
Sie können auch einen Leistungstest für eine Schleife durchführen, indem Sie diese öffnen
https://blogs.oracle.com/greimer/resource/loop-test.html
(funktioniert nicht, wenn JavaScript im Browser beispielsweise durch NoScript blockiert wird ).BEARBEITEN:
Ein neuerer Benchmark von Milan Adamovsky kann hier zur Laufzeit durchgeführt werden zur für verschiedene Browser durchgeführt werden.
Für einen Test in Firefox 17.0 unter Mac OS X 10.6 habe ich folgende Schleife erhalten:
als der schnellste vorangegangen von:
quelle
Es ist nicht das
--
oder++
, es ist die Vergleichsoperation. Mit können--
Sie einen Vergleich mit 0 verwenden, während++
Sie ihn mit der Länge vergleichen müssen. Auf dem Prozessor ist normalerweise ein Vergleich mit Null verfügbar, während ein Vergleich mit einer endlichen ganzen Zahl eine Subtraktion erfordert.a++ < length
ist eigentlich kompiliert als
Auf dem Prozessor dauert das Kompilieren also länger.
quelle
Kurze Antwort
Für normalen Code, insbesondere in einer Hochsprache wie JavaScript , gibt es keinen Leistungsunterschied in
i++
undi--
.Das Leistungskriterium ist die Verwendung in der
for
Schleife und der Vergleich .Dies gilt für alle Hochsprachen und ist weitgehend unabhängig von der Verwendung von JavaScript. Die Erklärung ist der resultierende Assembler-Code in der unteren Zeile.
Ausführliche Erklärung
In einer Schleife kann ein Leistungsunterschied auftreten. Der Hintergrund ist, dass Sie auf der Assembler-Codeebene sehen können, dass a
compare with 0
nur eine Anweisung ist, für die kein zusätzliches Register erforderlich ist.Dieser Vergleich wird bei jedem Durchlauf der Schleife ausgegeben und kann zu einer messbaren Leistungsverbesserung führen.
wird zu einem Pseudocode wie folgt ausgewertet :
Beachten Sie, dass 0 ein Literal oder mit anderen Worten ein konstanter Wert ist.
wird zu einem Pseudocode wie diesem ausgewertet (normale Interpreteroptimierung angenommen):
Beachten Sie, dass end eine Variable ist, die ein CPU- Register benötigt. Dies kann zu einem zusätzlichen Registeraustausch im Code führen und erfordert eine teurere Vergleichsanweisung in der
if
Anweisung.Nur meine 5 Cent
Für eine Hochsprache ist die Lesbarkeit, die die Wartbarkeit erleichtert, als geringfügige Leistungsverbesserung wichtiger.
Normalerweise ist die klassische Iteration vom Anfang bis zum Ende des Arrays besser.
Die schnellere Iteration vom Array- Ende bis zum Start führt zu der möglicherweise unerwünschten umgekehrten Reihenfolge.
Post scriptum
Wie in einem Kommentar gefragt: Der Unterschied von
--i
undi--
liegt in der Bewertung voni
vor oder nach dem Dekrementieren.Die beste Erklärung ist, es auszuprobieren ;-) Hier ist ein Bash- Beispiel.
quelle
--i
undi--
auch erklären ?Ich habe die gleiche Empfehlung in Sublime Text 2 gesehen.
Wie bereits gesagt, besteht die Hauptverbesserung nicht darin, die Länge des Arrays bei jeder Iteration in der for-Schleife zu bewerten. Dies ist eine bekannte Optimierungstechnik und besonders effizient in JavaScript , wenn die Array - Teil des HTML - Dokuments ist (dabei ein
for
für die alle dieli
Elemente ausgeführt wird).Zum Beispiel,
for (var i = 0; i < document.getElementsByTagName('li').length; i++)
ist viel langsamer als
for (var i = 0, len = document.getElementsByTagName('li').length; i < len; i++)
Aus meiner Sicht ist die Hauptverbesserung des Formulars in Ihrer Frage die Tatsache, dass es keine zusätzliche Variable deklariert (
len
in meinem Beispiel).Aber wenn Sie mich fragen, geht es nicht um die
i++
vs-i--
Optimierung, sondern darum, dass Sie nicht bei jeder Iteration die Länge des Arrays bewerten müssen (Sie können einen Benchmark-Test auf jsperf sehen ).quelle
Ich denke nicht, dass es Sinn macht zu sagen, dass
i--
das schneller gehti++
in JavaScript.Zuerst hängt es völlig von der Implementierung der JavaScript-Engine ab.
Zweitens hängt
i++
vsi--
vollständig von der CPU ab, die es ausführt , vorausgesetzt, dass einfachste Konstrukte JIT'ed und in native Anweisungen übersetzt werden . Das heißt, auf ARMs (Mobiltelefonen) ist es schneller, auf 0 zu fallen, da Dekrementieren und Vergleichen mit Null in einem einzigen Befehl ausgeführt werden.Wahrscheinlich haben Sie gedacht, dass einer verschwenderischer ist als der andere, weil der vorgeschlagene Weg dies ist
aber vorgeschlagener Weg ist nicht, weil einer schneller als der andere, sondern einfach, weil, wenn Sie schreiben
dann bei jeder Iteration
array.length
ausgewertet werden (eine intelligentere JavaScript-Engine könnte möglicherweise herausfinden, dass die Schleife die Länge des Arrays nicht ändert). Obwohl es wie eine einfache Anweisung aussieht, ist es tatsächlich eine Funktion, die von der JavaScript-Engine unter der Haube aufgerufen wird.Der andere Grund, warum
i--
dies als "schneller" angesehen werden könnte, ist, dass die JavaScript-Engine nur eine interne Variable zuweisen muss, um die Schleife zu steuern (Variable zuvar i
). Wenn Sie mit array.length oder einer anderen Variablen verglichen haben, musste es mehr als eine interne Variable geben, um die Schleife zu steuern, und die Anzahl der internen Variablen ist ein begrenztes Kapital einer JavaScript-Engine. Je weniger Variablen in einer Schleife verwendet werden, desto größer ist die Chance, dass JIT optimiert wird. Deshalbi--
könnte man schneller denken ...quelle
array.length
bewertet wird. Die Länge wird nicht berechnet, wenn Sie darauf verweisen. (Es ist nur eine Eigenschaft, die festgelegt wird, wenn ein Array-Index erstellt oder geändert wird. ) Wenn zusätzliche Kosten anfallen, liegt dies daran, dass die JS-Engine die Suchkette für diesen Namen nicht optimiert hat.getLength(){return m_length; }
da es sich um eine gewisse Haushaltsführung handelt. Aber wenn Sie versuchen, rückwärts zu denken: Das wäre ziemlich genial, um eine Array-Implementierung zu schreiben, bei der die Länge tatsächlich berechnet werden müsste :)length
muss sofort aktualisiert werden, wenn eine Eigenschaft, die ein Array-Index ist, hinzugefügt oder geändert wird.dec/jnz
vs.inc eax / cmp eax, edx / jne
.Da keine der anderen Antworten Ihre spezifische Frage zu beantworten scheint (mehr als die Hälfte von ihnen zeigt C-Beispiele und diskutiert Sprachen auf niedrigerer Ebene, Ihre Frage bezieht sich auf JavaScript), habe ich beschlossen, meine eigene zu schreiben.
Also los geht's:
Einfache Antwort: Ist
i--
im Allgemeinen schneller, da nicht jedes Mal ein Vergleich mit 0 durchgeführt werden muss. Die Testergebnisse für verschiedene Methoden sind unten aufgeführt:Testergebnisse: Wie von diesem jsPerf "bewiesen" ,
arr.pop()
ist es tatsächlich die mit Abstand schnellste Schleife. Aber, die sich auf--i
,i--
,i++
und++i
wie Sie in Ihrer Frage gestellt, hier sind jsPerf (sie von mehreren jsPerf der, beachten Sie bitte Quellen siehe unten) Ergebnisse zusammengefasst:--i
undi--
sind in Firefox gleich, währendi--
es in Chrome schneller ist.In Chrome ist ein Basic für loop (
for (var i = 0; i < arr.length; i++)
) schneller alsi--
und--i
in Firefox langsamer.Sowohl in Chrome als auch in Firefox wird zwischengespeichert
arr.length
mit Chrome um etwa 170.000 Ops / Sek. Deutlich schneller.Ohne signifikanten Unterschied
++i
isti++
AFAIK schneller als in den meisten Browsern, in keinem Browser ist es umgekehrt.Kürzere Zusammenfassung:
arr.pop()
ist bei weitem die schnellste Schleife; für die speziell genannten Schleifeni--
ist die schnellste Schleife.Quellen: http://jsperf.com/fastest-array-loops-in-javascript/15 , http://jsperf.com/ipp-vs-ppi-2
Ich hoffe das beantwortet deine Frage.
quelle
pop
Test nur so schnell zu sein scheint, weil er die Array-Größe für den größten Teil der Schleife auf 0 reduziert - soweit ich das beurteilen kann. Um jedoch sicherzustellen, dass die Dinge fair sind, habe ich diesen jsperf so entworfen, dass er das Array bei jedem Test auf die gleiche Weise erstellt - was sich.shift()
als Gewinner für meine wenigen Browser herausstellt++i
: DDies hängt von der Platzierung Ihres Arrays im Speicher und der Trefferquote der Speicherseiten ab, während Sie auf dieses Array zugreifen.
In einigen Fällen ist der Zugriff auf Array-Mitglieder in Spaltenreihenfolge aufgrund der Erhöhung der Trefferquote schneller als in der Zeilenreihenfolge.
quelle
Das letzte Mal habe ich mich darum gekümmert, als ich eine 6502- Assembly geschrieben habe (8-Bit, ja!). Der große Vorteil besteht darin, dass die meisten arithmetischen Operationen (insbesondere Dekremente) eine Reihe von Flags aktualisiert haben. Eines davon war
Z
der Indikator "erreicht Null".Am Ende der Schleife haben Sie also nur zwei Anweisungen ausgeführt:
DEC
(Dekrementieren) undJNZ
(Springen, wenn nicht Null), kein Vergleich erforderlich!quelle
i--
vsi++
ist höchstwahrscheinlich, dass Sie mit dem ersteren keine zusätzlichen Steuervariablen in den Bereich der Schleife einführen. Siehe meine Antwort unten ...dec/jnz
anstelleinc/cmp/jne
für den x86-Fall. Eine leere Schleife wird nicht schneller ausgeführt (beide sättigen den Zweigdurchsatz), aber durch Herunterzählen wird der Schleifen-Overhead geringfügig reduziert. Aktuelle Intel HW-Prefetchers stören sich auch nicht an Speicherzugriffsmustern, die in absteigender Reihenfolge ablaufen. Ältere CPUs könnten meiner Meinung nach 4 Rückwärtsströme und 6 oder 10 Vorwärtsströme, IIRC, verfolgen.Dies kann dadurch erklärt werden, dass JavaScript (und alle Sprachen) schließlich in Opcodes umgewandelt werden, die auf der CPU ausgeführt werden. CPUs haben immer einen einzigen Befehl zum Vergleichen mit Null, was verdammt schnell ist.
Als Nebenwirkung , wenn Sie garantieren können ,
count
ist immer>= 0
, Sie vereinfachen könnte:quelle
Dies hängt nicht vom Vorzeichen
--
oder ab++
, sondern von den Bedingungen, die Sie in der Schleife anwenden.Beispiel: Ihre Schleife ist schneller, wenn die Variable einen statischen Wert hat, als wenn Ihre Schleife jedes Mal Bedingungen wie die Länge eines Arrays oder andere Bedingungen überprüft.
Aber machen Sie sich keine Sorgen um diese Optimierung, da diesmal der Effekt in Nanosekunden gemessen wird.
quelle
for(var i = array.length; i--; )
ist nicht viel schneller. Aber wenn Sie ersetzenarray.length
mitsuper_puper_function()
, sein , dass möglicherweise erheblich schneller (da es in jeder Iteration genannt wird ). Das ist der Unterschied.Wenn Sie es 2014 ändern möchten, müssen Sie nicht über Optimierung nachdenken. Wenn Sie es mit "Suchen & Ersetzen" ändern möchten, müssen Sie nicht über Optimierung nachdenken. Wenn Sie keine Zeit haben, müssen Sie nicht über Optimierung nachdenken. Aber jetzt haben Sie Zeit, darüber nachzudenken.
PS:
i--
ist nicht schneller alsi++
.quelle
Um es kurz zu machen: In JavaScript gibt es absolut keinen Unterschied.
Zunächst können Sie es selbst testen:
jsperf - ist eine hervorragende Plattform für alle Arten von Leistungstests in JavaScript .
http://jsperf.com/inc-vs-dec-2
Sie können nicht nur jedes Skript in einer beliebigen JavaScript-Bibliothek testen und ausführen, sondern haben auch Zugriff auf die gesamte Reihe zuvor geschriebener Skripte sowie auf die Fähigkeit, Unterschiede zwischen der Ausführungszeit in verschiedenen Browsern auf verschiedenen Plattformen festzustellen.
Soweit Sie sehen, gibt es in keiner Umgebung einen Unterschied zwischen der Leistung.
Wenn Sie die Leistung Ihres Skripts verbessern möchten, können Sie Folgendes versuchen:
var a = array.length;
Anweisung, damit Sie ihren Wert nicht jedes Mal in der Schleife berechnenAber Sie müssen verstehen, dass die Verbesserung, die Sie erzielen können, so unbedeutend ist, dass Sie sich meistens nicht einmal darum kümmern sollten.
Meine eigene Meinung, warum ein solches Missverständnis (Dec vs Inc) aufgetreten ist
Vor langer, langer Zeit gab es eine gemeinsame Maschinenanweisung, DSZ (Decrement and Skip on Zero). Personen, die in Assemblersprache programmiert haben, haben diese Anweisung verwendet, um Schleifen zu implementieren, um ein Register zu speichern. Jetzt sind diese alten Fakten überholt, und ich bin mir ziemlich sicher, dass Sie mit dieser Pseudoverbesserung in keiner Sprache eine Leistungsverbesserung erzielen werden.
Ich denke, der einzige Weg, wie sich solches Wissen in unserer Zeit verbreiten kann, ist, wenn Sie den Personencode eines anderen lesen. Sehen Sie sich eine solche Konstruktion an und fragen Sie, warum sie implementiert wurde. Hier die Antwort: "Sie verbessert die Leistung, weil sie mit Null verglichen wird." Sie waren verwirrt über das höhere Wissen Ihres Kollegen und denken, es zu nutzen, um viel schlauer zu sein :-)
quelle
array.length
führt nicht unbedingt zu Leistungseinbußen, da die virtuelle JS-Maschine intelligent genug ist, um herauszufinden, ob das Array nicht vom Hauptteil der Schleife geändert wird. Siehe meine Antwort unten.Ich habe einen Vergleich auf jsbench gemacht .
Wie Alestani betonte, besteht eine Sache, die in aufsteigenden Schleifen einige Zeit in Anspruch nimmt, darin, für jede Iteration die Größe Ihres Arrays zu bewerten. In dieser Schleife:
Sie bewerten
.length
jedes Mal, wenn Sie inkrementiereni
. In diesem:Sie bewerten
.length
nur einmal, wenn Sie deklariereni
. In diesem:Der Vergleich ist implizit, erfolgt kurz vor dem Dekrementieren
i
und der Code ist sehr gut lesbar. Was jedoch einen großen Unterschied machen kann, ist das, was Sie in die Schleife einfügen.Schleife mit Funktionsaufruf (an anderer Stelle definiert):
Schleife mit Inline-Code:
Wenn Sie Ihren Code einbinden können, anstatt eine Funktion aufzurufen, ohne die Lesbarkeit zu beeinträchtigen, können Sie eine Schleife um eine Größenordnung schneller erstellen!
Hinweis : Da der Browser einfache Funktionen immer besser einbinden kann, hängt dies wirklich davon ab, wie komplex Ihr Code ist. Also, Profil vor der Optimierung, weil
Aber erinnere dich:
quelle
Die Art und Weise, wie Sie es jetzt tun, ist nicht schneller (abgesehen davon, dass es sich um eine unbestimmte Schleife handelt, haben Sie das wohl vorgehabt
i--
.Wenn Sie es schneller machen möchten, tun Sie Folgendes:
Natürlich würden Sie es auf einer so kleinen Schleife nicht bemerken. Der Grund, warum es schneller ist, ist, dass Sie i dekrementieren, während Sie überprüfen, ob es "wahr" ist (es wird als "falsch" ausgewertet, wenn es 0 erreicht).
quelle
(i = 10; i--;)
Manchmal können geringfügige Änderungen an der Art und Weise, wie wir unseren Code schreiben, einen großen Unterschied darin machen, wie schnell unser Code tatsächlich ausgeführt wird. Ein Bereich, in dem eine geringfügige Codeänderung einen großen Unterschied zu den Ausführungszeiten bewirken kann, ist der Bereich, in dem eine for-Schleife ein Array verarbeitet. Wenn das Array aus Elementen auf der Webseite besteht (z. B. Optionsfelder), hat die Änderung den größten Effekt. Es lohnt sich jedoch, diese Änderung auch dann anzuwenden, wenn sich das Array im Javascript-Code befindet.
Die herkömmliche Art der Codierung einer for-Schleife zur Verarbeitung eines Arrays lautet wie folgt:
Das Problem dabei ist, dass das Auswerten der Länge des Arrays mit myArray.length Zeit braucht und die Art und Weise, wie wir die Schleife codiert haben, bedeutet, dass diese Auswertung jedes Mal um die Schleife herum durchgeführt werden muss. Wenn das Array 1000 Elemente enthält, wird die Länge des Arrays 1001 Mal ausgewertet. Wenn wir Optionsfelder betrachtet haben und myForm.myButtons.length hatten, dauert die Auswertung noch länger, da die entsprechende Gruppe von Schaltflächen innerhalb des angegebenen Formulars zuerst gefunden werden muss, bevor die Länge jedes Mal um die Schleife herum ausgewertet werden kann.
Offensichtlich erwarten wir nicht, dass sich die Länge des Arrays während der Verarbeitung ändert, sodass all diese Neuberechnungen der Länge die Verarbeitungszeit nur unnötig verlängern. (Wenn Sie Code in der Schleife haben, der Array-Einträge hinzufügt oder entfernt, kann sich die Array-Größe zwischen den Iterationen ändern, sodass wir den Code, der darauf testet, nicht ändern können.)
Um dies für eine Schleife zu korrigieren, bei der die Größe festgelegt ist, müssen wir die Länge einmal am Anfang der Schleife auswerten und in einer Variablen speichern. Wir können dann die Variable testen, um zu entscheiden, wann die Schleife beendet werden soll. Dies ist viel schneller als die Auswertung der Array-Länge jedes Mal, insbesondere wenn das Array mehr als nur wenige Einträge enthält oder Teil der Webseite ist.
Der Code dafür lautet:
Jetzt bewerten wir die Größe des Arrays nur noch einmal und testen unseren Schleifenzähler anhand der Variablen, die diesen Wert jedes Mal um die Schleife herum enthält. Auf diese zusätzliche Variable kann viel schneller zugegriffen werden als durch Auswerten der Größe des Arrays, sodass unser Code viel schneller als zuvor ausgeführt wird. Wir haben nur eine zusätzliche Variable in unserem Skript.
Oft spielt es keine Rolle, in welcher Reihenfolge wir das Array verarbeiten, solange alle Einträge im Array verarbeitet werden. In diesem Fall können wir unseren Code etwas schneller machen, indem wir die gerade hinzugefügte zusätzliche Variable entfernen und das Array in umgekehrter Reihenfolge verarbeiten.
Der endgültige Code, der unser Array so effizient wie möglich verarbeitet, lautet:
Dieser Code wertet die Größe des Arrays immer noch nur einmal zu Beginn aus, aber anstatt den Schleifenzähler mit einer Variablen zu vergleichen, vergleichen wir ihn mit einer Konstanten. Da der Zugriff auf eine Konstante noch effektiver ist als auf eine Variable und wir eine Zuweisungsanweisung weniger haben als zuvor, ist unsere dritte Version des Codes jetzt etwas effizienter als die zweite Version und weitaus effizienter als die erste.
quelle
++
vs.--
spielt keine Rolle, da JavaScript eine interpretierte Sprache ist, keine kompilierte Sprache. Jede Anweisung wird in mehr als eine Maschinensprache übersetzt, und Sie sollten sich nicht um die blutigen Details kümmern.Menschen, die über die Verwendung
--
(oder++
) zur effizienten Nutzung von Montageanweisungen sprechen, sind falsch. Diese Anweisungen gelten für Ganzzahlarithmetik und es gibt keine Ganzzahlen in JavaScript, nur Zahlen .Sie sollten lesbaren Code schreiben.
quelle
In vielen Fällen hat dies im Wesentlichen nichts damit zu tun, dass Prozessoren schneller als andere Vergleiche mit Null vergleichen können.
Dies liegt daran, dass nur wenige Javascript-Engines (die in der JIT-Liste) tatsächlich Maschinensprachencode generieren.
Die meisten Javascript-Engines erstellen eine interne Darstellung des Quellcodes, den sie dann interpretieren (um eine Vorstellung davon zu bekommen, wie dies aussieht, werfen Sie einen Blick auf den SpiderMonkey von Firefox am Ende dieser Seite ). Wenn ein Code praktisch dasselbe tut, aber zu einer einfacheren internen Darstellung führt, wird er im Allgemeinen schneller ausgeführt.
Denken Sie daran, dass bei einfachen Aufgaben wie dem Addieren / Subtrahieren einer Variablen zu einer Variablen oder dem Vergleichen einer Variablen mit etwas der Overhead des Interpreters, der von einer internen "Anweisung" zur nächsten wechselt, ziemlich hoch ist, also weniger "Anweisungen" intern von der JS-Engine verwendet, desto besser.
quelle
Nun, ich weiß nichts über JavaScript, es sollte eigentlich nur eine Frage der Neubewertung der Array-Länge sein und vielleicht etwas mit den assoziativen Arrays zu tun haben (wenn Sie nur dekrementieren, ist es unwahrscheinlich, dass neue Einträge zugewiesen werden müssen - wenn das Array ist dicht, das heißt, jemand kann dafür optimieren).
Bei der Montage auf niedriger Ebene gibt es eine Schleifenanweisung namens DJNZ (Dekrementieren und Springen, wenn nicht Null). Das Dekrementieren und Springen ist also alles in einer Anweisung, was es möglicherweise etwas schneller als INC und JL / JB macht (Inkrementieren, Springen, wenn kleiner als / Springen, wenn unten). Außerdem ist der Vergleich mit Null einfacher als der Vergleich mit einer anderen Zahl. Aber all das ist wirklich marginal und hängt auch von der Zielarchitektur ab (könnte einen Unterschied machen, z. B. bei Arm in einem Smartphone).
Ich würde nicht erwarten, dass diese geringen Unterschiede einen so großen Einfluss auf interpretierte Sprachen haben. Ich habe DJNZ einfach nicht in den Antworten gesehen, also dachte ich, ich würde einen interessanten Gedanken teilen.
quelle
DJNZ
ist eine Anweisung in der 8051 (z80) ISA. x86 hatdec/jnz
stattinc/cmp/jne
und anscheinend hat arm etwas ähnliches. Ich bin mir ziemlich sicher, dass dies nicht die Ursache für den Unterschied in Javascript ist. Das liegt daran, dass im Loop-Zustand mehr zu bewerten ist.Es verwendet zu sagen, dass --i schneller war (in C ++) , weil es nur ein Ergebnis der verringerten Wert. i-- muss den dekrementierten Wert wieder auf i speichern und als Ergebnis auch den ursprünglichen Wert beibehalten (j = i--;). In den meisten Compilern wurden zwei Register anstelle von einem verwendet, was dazu führen könnte, dass eine andere Variable in den Speicher geschrieben werden muss, anstatt als Registervariable beibehalten zu werden.
Ich stimme den anderen zu, die gesagt haben, dass es heutzutage keinen Unterschied macht.
quelle
In sehr einfachen Worten
"i-- und i ++. Eigentlich dauert es beide die gleiche Zeit".
Aber in diesem Fall, wenn Sie eine inkrementelle Operation haben, wertet der Prozessor die Länge jedes Mal aus, wenn die Variable um 1 erhöht wird, und im Falle einer Dekrementierung. Insbesondere in diesem Fall wird die Länge nur einmal ausgewertet, bis wir 0 erhalten.
quelle
Erstens,
i++
undi--
nehmen Sie sich für jede Programmiersprache, einschließlich JavaScript, genau die gleiche Zeit.Der folgende Code benötigt eine sehr unterschiedliche Zeit.
Schnell:
Langsam:
Daher dauert der folgende Code auch anders.
Schnell:
Langsam:
PS Slow ist aufgrund der Optimierung des Compilers nur für einige Sprachen (JavaScript-Engines) langsam. Der beste Weg ist, '<' anstelle von '<=' (oder '=') und '--i' anstelle von 'i--' zu verwenden .
quelle
I-- oder i ++ verbrauchen nicht viel Zeit. Wenn Sie tief in die CPU-Architektur eintauchen, ist die
++
schneller als die--
, da die--
Operation das 2er-Komplement ausführt, aber sie geschieht innerhalb der Hardware, so dass sie schneller wird und kein wesentlicher Unterschied zwischen den++
und--
auch diesen Operationen berücksichtigt wird am wenigsten Zeit in der CPU verbraucht.Die for-Schleife läuft folgendermaßen ab:
<
,>
,<=
usw.So,
berechnet die Array-Länge nur einmal zu Beginn und das ist nicht viel Zeit, aber
berechnet die Länge an jeder Schleife, so dass viel Zeit verbraucht wird.
quelle
var i = Things.length - 1; i >= 0; i--
berechnet die Länge auch 1 Mal.--
Operation macht das 2er-Komplement" bedeutet, aber ich gehe davon aus, dass es bedeutet, dass es etwas negiert. Nein, es negiert nichts auf irgendeiner Architektur. Das Subtrahieren von 1 ist genauso einfach wie das Addieren von 1, Sie erstellen einfach eine Schaltung, die eher leiht als trägt.Der beste Ansatz zur Beantwortung dieser Art von Fragen besteht darin, sie tatsächlich zu versuchen. Richten Sie eine Schleife ein, die eine Million Iterationen oder was auch immer zählt, und führen Sie sie in beide Richtungen aus. Zeit beide Schleifen und vergleichen Sie die Ergebnisse.
Die Antwort hängt wahrscheinlich davon ab, welchen Browser Sie verwenden. Einige haben andere Ergebnisse als andere.
quelle
Ich liebe es, viele Punkte, aber keine Antwort: D.
Einfach ein Vergleich gegen Null ist immer der schnellste Vergleich
(A == 0) gibt also tatsächlich schneller True zurück als (a == 5)
Es ist klein und unbedeutend und mit 100 Millionen Zeilen in einer Sammlung messbar.
dh in einer Schleife nach oben könnten Sie sagen, wo i <= array.length und i inkrementieren
In einer Abwärtsschleife könnten Sie sagen, wo i> = 0 ist, und stattdessen i dekrementieren.
Der Vergleich ist schneller. Nicht die 'Richtung' der Schleife.
quelle
HILFE ANDEREN, EINEN KOPFSCHMERZ ZU VERMEIDEN --- ABSTIMMEN !!!
Die beliebteste Antwort auf dieser Seite funktioniert nicht für Firefox 14 und besteht den jsLinter nicht. "while" -Schleifen benötigen einen Vergleichsoperator, keine Zuordnung. Es funktioniert auf Chrom, Safari und sogar dh. Aber stirbt in Firefox.
DAS IST KAPUTT!
DAS WIRD FUNKTIONIEREN! (funktioniert auf Firefox, übergibt den jsLinter)
quelle
while (i--)
die in vielen Browsern verwendet werden und funktionieren. Könnte an Ihrem Test etwas Seltsames gewesen sein? Haben Sie eine Beta-Version von Firefox 14 verwendet?Dies ist nur eine Vermutung, aber vielleicht liegt es daran, dass es für den Prozessor einfacher ist, etwas mit 0 (i> = 0) zu vergleichen, als mit einem anderen Wert (i <Things.length).
quelle