Die mit Arrays und Objekten in JavaScript (insbesondere Google V8) verbundene Leistung wäre sehr interessant zu dokumentieren. Ich finde nirgendwo im Internet einen umfassenden Artikel zu diesem Thema.
Ich verstehe, dass einige Objekte Klassen als zugrunde liegende Datenstruktur verwenden. Wenn es viele Eigenschaften gibt, wird es manchmal als Hash-Tabelle behandelt?
Ich verstehe auch, dass Arrays manchmal wie C ++ - Arrays behandelt werden (dh schnelle zufällige Indizierung, langsames Löschen und Ändern der Größe). In anderen Fällen werden sie eher wie Objekte behandelt (schnelle Indizierung, schnelles Einfügen / Entfernen, mehr Speicher). Und vielleicht werden sie manchmal als verknüpfte Listen gespeichert (dh langsame zufällige Indizierung, schnelles Entfernen / Einfügen am Anfang / Ende)
Was ist die genaue Leistung von Array- / Objektabrufen und -manipulationen in JavaScript? (speziell für Google V8)
Genauer gesagt, welche Auswirkungen hat dies auf die Leistung:
- Hinzufügen einer Eigenschaft zu einem Objekt
- Entfernen einer Eigenschaft aus einem Objekt
- Indizieren einer Eigenschaft in einem Objekt
- Hinzufügen eines Elements zu einem Array
- Entfernen eines Elements aus einem Array
- Indizieren eines Elements in einem Array
- Array.pop () aufrufen
- Array.push () aufrufen
- Array.shift () aufrufen
- Array.unshift () aufrufen
- Array.slice () aufrufen
Alle Artikel oder Links für weitere Details sind ebenfalls willkommen. :) :)
EDIT: Ich frage mich wirklich, wie JavaScript-Arrays und -Objekte unter der Haube funktionieren. In welchem Kontext "weiß" die V8-Engine, auf eine andere Datenstruktur "umzuschalten"?
Angenommen, ich erstelle ein Array mit ...
var arr = [];
arr[10000000] = 20;
arr.push(21);
Was ist hier wirklich los?
Oder ... was ist damit ... ???
var arr = [];
//Add lots of items
for(var i = 0; i < 1000000; i++)
arr[i] = Math.random();
//Now I use it like a queue...
for(var i = 0; i < arr.length; i++)
{
var item = arr[i].shift();
//Do something with item...
}
Bei herkömmlichen Arrays wäre die Leistung schrecklich. wohingegen, wenn eine LinkedList verwendet wurde ... nicht so schlecht.
quelle
Antworten:
Ich habe eine Testsuite erstellt, um genau diese (und weitere) Probleme zu untersuchen ( archivierte Kopie ).
In diesem Sinne können Sie die Leistungsprobleme in diesem Testfalltester über 50 sehen (es wird lange dauern).
Wie der Name schon sagt, wird die Verwendung der nativen verknüpften Listennatur der DOM-Struktur untersucht.
(Derzeit nicht verfügbar, wird gerade umgebaut.) Weitere Details dazu in meinem Blog .
Die Zusammenfassung ist wie folgt
Array.shift()
ist es ungefähr 6x langsamer als ein Array-Pop, aber ungefähr 100x schneller als das Löschen von Objektattributen.Array.push( data );
ist es schneller alsArray[nextIndex] = data
fast 20 (dynamisches Array) bis 10 (festes Array) Mal.Array.unshift(data)
ist langsamer als erwartet und ~ ca. 5x langsamer als das Hinzufügen einer neuen Eigenschaft.array[index] = null
ist schneller als das Löschendelete array[index]
(undefiniert) in einem Array um ~ ca. 4x ++ schneller.obj[attr] = null
ca. 2x langsamer als das Löschen des Attributsdelete obj[attr]
Array.splice(index,0,data)
langsam und sehr langsam ist.Array.splice(index,1,data)
wurde optimiert (keine Längenänderung) und ist 100x schneller als nur SpleißenArray.splice(index,0,data)
dll.splice(index,1)
Entfernung (wo das Testsystem beschädigt wurde ).Hinweis: Diese Metriken gelten nur für große Arrays / Objekte, die in Version 8 nicht "vollständig optimiert" werden. Es kann sehr isolierte optimierte Leistungsfälle für Array- / Objektgrößen geben, die kleiner als eine beliebige Größe (24?) Sind. Weitere Details finden Sie in mehreren Google IO-Videos.
Hinweis 2: Diese wunderbaren Leistungsergebnisse werden nicht von allen Browsern, insbesondere dem
*cough*
Internet Explorer, geteilt. Auch der Test ist riesig, daher muss ich die Ergebnisse noch vollständig analysieren und bewerten: Bitte bearbeiten Sie ihn in =)Aktualisierter Hinweis (Dezember 2012): Google-Vertreter haben Videos auf youtubes, in denen das Innenleben von Chrome selbst (z. B. beim Wechsel von einem verknüpften Listenarray zu einem festen Array usw.) und deren Optimierung beschrieben werden. Weitere Informationen finden Sie unter GDC 2012: Von der Konsole zu Chrome .
quelle
Auf einer grundlegenden Ebene, die im Bereich von JavaScript bleibt, sind Eigenschaften von Objekten viel komplexere Entitäten. Sie können Eigenschaften mit Setzern / Gettern mit unterschiedlicher Aufzählbarkeit, Beschreibbarkeit und Konfigurierbarkeit erstellen. Ein Element in einem Array kann nicht auf diese Weise angepasst werden: Es ist entweder vorhanden oder nicht. Auf der zugrunde liegenden Engine-Ebene ermöglicht dies eine wesentlich bessere Optimierung hinsichtlich der Organisation des Speichers, der die Struktur darstellt.
In Bezug auf die Identifizierung eines Arrays aus einem Objekt (Wörterbuch) haben JS-Engines immer explizite Linien zwischen den beiden gezogen. Aus diesem Grund gibt es eine Vielzahl von Artikeln über Methoden zum Erstellen eines semi-gefälschten Array-ähnlichen Objekts, das sich wie eines verhält, aber andere Funktionen zulässt. Der Grund, warum diese Trennung überhaupt besteht, ist, dass die JS-Engines die beiden unterschiedlich speichern.
Eigenschaften können in einem Array-Objekt gespeichert werden. Dies zeigt jedoch lediglich, wie JavaScript darauf besteht, alles zu einem Objekt zu machen. Die indizierten Werte in einem Array werden anders gespeichert als alle Eigenschaften, die Sie für das Array-Objekt festlegen, das die zugrunde liegenden Array-Daten darstellt.
Immer wenn Sie ein legitimes Array-Objekt verwenden und eine der Standardmethoden zum Bearbeiten dieses Arrays verwenden, werden Sie auf die zugrunde liegenden Array-Daten stoßen. Insbesondere in V8 entsprechen diese im Wesentlichen einem C ++ - Array, sodass diese Regeln gelten. Wenn Sie aus irgendeinem Grund mit einem Array arbeiten, das die Engine nicht mit Sicherheit als Array bestimmen kann, befinden Sie sich auf einem viel wackeligeren Boden. Mit den neuesten Versionen von V8 gibt es jedoch mehr Platz zum Arbeiten. Beispielsweise ist es möglich, eine Klasse zu erstellen, deren Prototyp Array.prototype ist, und dennoch effizienten Zugriff auf die verschiedenen nativen Array-Manipulationsmethoden zu erhalten. Dies ist jedoch eine kürzliche Änderung.
Spezifische Links zu den letzten Änderungen an der Array-Manipulation können hier nützlich sein:
Als kleines Extra sind hier Array Pop und Array Push direkt aus der V8-Quelle, beide in JS selbst implementiert:
quelle
Ich möchte vorhandene Antworten durch eine Untersuchung der Frage ergänzen, wie sich Implementierungen in Bezug auf wachsende Arrays verhalten: Wenn sie auf die "übliche" Weise implementiert werden, würde man viele schnelle Pushs mit seltenen, eingestreuten langsamen Pushs sehen, an welchem Punkt die Implementierung kopiert die interne Darstellung des Arrays von einem Puffer zu einem größeren.
Sie können diesen Effekt sehr gut sehen, dies ist von Chrome:
Obwohl jeder Push profiliert ist, enthält die Ausgabe nur diejenigen, die über einem bestimmten Schwellenwert Zeit benötigen. Für jeden Test habe ich den Schwellenwert so angepasst, dass alle Pushs ausgeschlossen werden, die die schnellen Pushs darstellen.
Die erste Zahl gibt also an, welches Element eingefügt wurde (die erste Zeile steht für das 17. Element), die zweite gibt an, wie lange es gedauert hat (für viele Arrays wird der Benchmark parallel durchgeführt), und der letzte Wert ist die Division des erste Zahl durch die in der vorherigen Zeile.
Alle Zeilen mit einer Ausführungszeit von weniger als 2 ms sind für Chrome ausgeschlossen.
Sie können sehen, dass Chrome die Array-Größe in Potenzen von 1,5 plus einen gewissen Versatz erhöht, um kleine Arrays zu berücksichtigen.
Für Firefox ist es eine Zweierpotenz:
Ich musste die Schwelle in Firefox ziemlich hoch legen, deshalb fangen wir bei # 126 an.
Mit IE bekommen wir eine Mischung:
Es ist zuerst eine Zweierpotenz und dann eine Potenz von fünf Dritteln.
Daher verwenden alle gängigen Implementierungen den "normalen" Weg für Arrays (anstatt zum Beispiel mit Seilen verrückt zu werden ).
Hier ist der Benchmark-Code und hier ist die Geige , in der er sich befindet.
quelle
Während der Ausführung unter node.js 0.10 (basierend auf Version 8) wurde eine CPU-Auslastung festgestellt, die für die Arbeitslast zu hoch schien. Ich habe ein Leistungsproblem auf eine Funktion zurückgeführt, die das Vorhandensein einer Zeichenfolge in einem Array überprüft hat. Also habe ich einige Tests durchgeführt.
Das Laden von 91k-Einträgen in ein Array (mit validate & push) ist schneller als das Setzen von obj [key] = value.
Im nächsten Test habe ich jeden Hostnamen in der Liste einmal nachgeschlagen (91.000 Iterationen, um die Suchzeit zu mitteln):
Die Anwendung hier ist Haraka (ein SMTP-Server). Sie lädt die host_list einmal beim Start (und nach Änderungen) und führt diese Suche anschließend während des Betriebs millionenfach durch. Der Wechsel zu einem Objekt war ein großer Leistungsgewinn.
quelle