Michael Kuhn: Speicher und Performance Frage für Javascript

Hallo,

ich bin gerade dabei, eine doch umfangreichere Web-Anwendung mit javascript zu realisieren. Bei der Anwendung werden eine Menge Daten ausgelesen und verarbeitet, zum Teil muss dass auch mit Web Worker realisiert werden, da sonst die Analyse den Browser zum einfrieren bringt.

Die vorliegenden Daten - in einer Art Tabellenform in einem Array vorliegend - sind unnötig groß, z.B. werden für identifiers sehr lange Zeichenketten verwendet 70 Zeichen und mehr sind keine Seltenheit. Ich denke nun darüber nach, ob man nicht vor der Auswertung und Analyse der Arrays einige Anpassungen vornehmen sollte, um die Datengröße zu minimieren und somit eventuell Performance Gewinne zu erzielen. Die Frage meinerseits - lohnt sich das Ganze in Javascript? Ich könnte mir Vorstellen, dass man dadurch etwas den Arbeitsspeicher auf Mobile-Geräten schont, sofern man die JS Engine dazu bekommt, den Speciher freizugeben. Hat jemand Erfahrungen auf dem Gebiet, ob sich es lohnt, bzw. was sind die Performance Tipps für große Datenmenegen. Ich spreche hier nicht vom DOM sondern das Analysieren von Daten in Array oder objects. Bringt es etwas zB etwas, die längeren Zeichenketten von identifiers in kürzer Zeichenketten umzuwandeln?

Wäre dankbar, wenn mir jemand weiterhelfen könnte. Mir ist klar, dass man sehr viel Performance bei der Abarbeitung der Daten herausholen kann. Mir geht es aber grundsätzlich darum, ob man die Daten vorher noch in der Größe optimieren sollte.

  1. Hallo!

    Bringt es etwas zB etwas, die längeren Zeichenketten von identifiers in kürzer Zeichenketten umzuwandeln?

    Strings und String-Eigenschaftsnamen werden intern als UTF-16 abgespeichert und jedes Zeichen verbraucht mindestens zwei Bytes. Natürlich lohnt es sich, diese Daten einzusparen. Die Einsparungen lassen sich berechnen und durch Heap-Snapshots auch nachvollziehen. Wie viel das im Vergleich zu den Gesamtdaten ist, steht auf einem anderen Blatt. Vielleicht kannst du mit den Identifiern nur ein paar Prozent sparen. Zudem musst du vermutlich irgendwo Hash-Algorithmen nutzen, um die langen Strings auf kurze abzubilden. Du erkaufst dir den Speicher-Vorteil ggf. durch einen Performance-Nachteil anderswo.

    Beim Übergeben von Daten an WebWorker muss ein gewisses Serialisieren oder Marshalling vorgenommen werden. Früher ließen sich mit postMessage nur Strings an den Worker schicken, mittlerweile beherrschen die Browser auch einfache Objekte mit den in JSON unterstützten Datentypen. Trotzdem muss der Browser diese Objekte traversieren, siehe Structured clone algorithm. Je kleiner die Objekte sind, desto schneller geht das und desto weniger Speicher wird benötigt. Im Prinzip können die Browser hier Copy on Write verwenden, anstatt das Objekt im Speicher zu verdoppeln. Aber davon würde ich im Zusammenhang mit WebWorkern nicht ausgehen, denn diese haben ihre eigene Sandbox.

    Generell würde ich ein sequenzielles Verarbeiten von Daten empfehlen, sodass du nie große Datenmengen im Speicher hast, sondern immer ein begrenztes Set an Arbeitsdaten, das du schnell reduzierst. Ich nehme an, du machst eine Art Map/Reduce? Woher kommen die Daten denn her und wo gehen die Analyseresultate hin?

    Grüße,
    Mathias

    1. Hallo Mathias,

      vielen Dank für die sehr hilfreichen Informationen. Ich glaube zudem auch eine Ursache in deinen Erläuterungen gefunden zu haben, warum in manchen Fällen die Anwendung auf einem Mobilgeräte z.Z. noch abstürzt, es könnte in der Tat der fehlende Speicher sein. Da bisher die Daten beim web worker nur per postMessage transferiert werden (da noch nicht alle weit verbreiteten Browser oauch den Austausch über objekte können).

      Ich werde jetzt auf jeden Fall einmal probieren, was der trade-off zwischen einer vorgeschalteter Datenoptimierung ist. Gegenwärtig ist es von mir auf Grund der Anwendung so gewählt, dass ich einen web worker öffne und die kompletten Daten zuweise, den web worker aber "offen" lasse und nicht für jede neue Abfrage die Daten noch einmal schicke. Der web worker ist ja gerade deshalb notwendig, weil die Auswertung über die gesamten Daten zu führen sind und daher eine Verkleinerung ausserhalb des web worker schon zu einem freeze des UI führen könnte. Der web worker schickt nur das entsprechende Ergebnis zurück und nicht noch einmal die kompletten Daten (ich denke das kommt dem map/reduce Gedanken nahe). Konkret nutze ich die taffyDB database library im web worker um Auswertungen zu fahren und das Ergebnis auszugeben. Funktioniert soweit ganz gut, nur eben ist es jetzt daran, an dem Performancerad zu drehen.

      Deinen Ausführungen entnehme ich aber auch, dass es nicht sinnvoll für javascript erscheint, den Datentype für Identifier zu ändern, etwa in integer?? Man müsste wohl dazu mehr wissen, ob eine gewissen Struktur vom JIT als solche erkannt wird. Ich hatte einen Vortrag zur V8 von Google mir angeschaut, wo darauf verwiesen wurde, dass man in Javascript auch darauf achten sollte, wie man gewisse Funktionen schreibt, da im Idealfall die Javascript-Engine das soweit optimieren kann, damit man nahe an die Performance von typisierten Sprachen herankommt. Aber das ist zum jetztigen Zeitpunkt für das Projekt noch alles etwas zu viel Aufwand. Ich werde es erst einmal versuchen, allein den Datenumfang zu reduzieren.

      Cheers,
      Michael

      PS: Solche performance Tipps sollte auch mal auf bei selfghtml.org für Javascript gesammelt werden. Ich bin da nicht der Einzige, der ein Interesse an solchen Information hat und das Internet nur sehr verstreut Information dazu bereithält.