Wie wir die Webanwendung mit Hilfe von WebAssembly um das 20-Fache beschleunigt haben

Wie wir die Webanwendung mit Hilfe von WebAssembly um das 20-Fache beschleunigt haben

In diesem Artikel wird der Fall beschrieben, wie man eine browserbasierte Anwendung beschleunigen kann, indem man Berechnungen in JavaScript durch WebAssembly ersetzt.

Was ist WebAssembly?

Kurz gesagt, es handelt sich um ein binäres Format für Anweisungen einer stackbasierten virtuellen Maschine. Oft wird Wasm (die Abkürzung) als Programmiersprache bezeichnet, was jedoch nicht zutrifft. Das Anweisungsformat wird im Browser zusammen mit JavaScript ausgeführt.

Es ist wichtig zu beachten, dass WebAssembly durch die Kompilierung von Quellcode in Programmiersprachen wie C/C++, Rust und Go erzeugt werden kann. Hierbei kommt eine statische Typisierung und ein sogenanntes flaches Speichermodell zum Einsatz. Der Code, wie bereits erwähnt, wird in einem kompakten binären Format gespeichert, wodurch er fast genauso schnell ausgeführt wird, als ob die Anwendung über die Kommandozeile gestartet worden wäre. Diese Eigenschaften haben zur wachsenden Popularität von WebAssembly beigetragen.

Wir erinnern daran: alle Leser von „Habr“ erhalten einen Rabatt von 10.000 Rubel bei der Anmeldung zu einem beliebigen Kurs von Skillbox mit dem Aktionscode „Habr“.

Skillbox empfiehlt: Praktischer Kurs „Mobile Entwickler PRO“.

Derzeit wird Wasm in vielen Anwendungen eingesetzt, von Spielen wie Doom 3 bis hin zu in das Web portierten Anwendungen wie Autocad und Figma. Wasm findet auch in Bereichen wie serverlosen Berechnungen Anwendung.

In diesem Artikel wird ein Beispiel für die Nutzung von Wasm zur Beschleunigung eines analytischen Webdienstes vorgestellt. Zu Illustrationszwecken verwenden wir eine funktionierende Anwendung, die in C geschrieben ist und in WebAssembly kompiliert wird. Das Ergebnis wird zur Optimierung wenig leistungsfähiger JavaScript-Abschnitte verwendet.

Transformation der Anwendung

Im Beispiel wird der browserbasierte Dienst fastq.bio verwendet, der für Genetiker konzipiert ist. Das Tool ermöglicht die Bewertung der Sequenzierungsqualität von DNA.

Hier ist ein Beispiel der Anwendung in Aktion:

Wie wir die Webanwendung mit Hilfe von WebAssembly um das 20-Fache beschleunigt haben

Die Details des Prozesses müssen nicht im Einzelnen erläutert werden, da sie für Laien ziemlich komplex sind. Kurz zusammengefasst können Wissenschaftler anhand der oben genannten Infografik herausfinden, ob der DNA-Sequenzierungsprozess reibungslos verlief und welche Probleme auftraten.

Dieser Dienst hat Desktop-Alternativen. Doch fastq.bio ermöglicht eine schnellere Verarbeitung durch die Visualisierung der Daten. In den meisten anderen Fällen ist Erfahrung mit der Befehlszeile erforderlich, aber nicht alle Genetiker verfügen über die nötigen Kenntnisse.

Alles funktioniert ganz einfach. Der Eingang sind Daten, die in Form einer Textdatei vorliegen. Diese Datei wird von spezialisierten Sequenzierungswerkzeugen generiert. In der Datei befindet sich eine Liste von DNA-Sequenzen sowie eine Qualitätsbewertung für jedes Nukleotid. Das Dateiformat ist .fastq, weshalb der Service diesen Namen trägt.

Implementierung in JavaScript

Der erste Schritt des Nutzers bei der Arbeit mit fastq.bio ist die Auswahl der entsprechenden Datei. Mit Hilfe des File-Objekts liest die Anwendung eine zufällige Auswahl von Daten aus der Datei und verarbeitet dieses Paket. Die Aufgabe von JavaScript dabei besteht in der Durchführung einfacher String-Operationen und der Berechnung von Kennzahlen. Eine davon ist die Anzahl der Nukleotide A, C, G und T in verschiedenen DNA-Fragmenten.

Nach der Berechnung der erforderlichen Parameter werden diese mithilfe von Plotly.js visualisiert, und der Dienst beginnt, mit dem neuen Datensatz zu arbeiten. Die Segmentierung wurde zur Verbesserung der Benutzererfahrung vorgenommen. Wenn man mit allen Daten gleichzeitig arbeitet, könnte der Prozess einige Zeit hängen bleiben, da die Dateien mit den Sequenzierungsergebnissen Hunderte von Gigabyte Speicherplatz beanspruchen. Der Dienst verarbeitet daher Datenstücke von 0,5 bis 1 MB und arbeitet schrittweise damit, um grafische Daten zu erstellen.

So funktioniert es:

Wie wir die Webanwendung mit Hilfe von WebAssembly um das 20-Fache beschleunigt haben

Im roten Rechteck befindet sich der Algorithmus für die Zeichenfolgenumwandlung zur Erstellung der Visualisierung. Dies ist der rechenintensivste Teil des Dienstes. Es wäre ratsam, ihn durch Wasm zu ersetzen.

WebAssembly testen

Um die Möglichkeiten der Nutzung von Wasm zu bewerten, beschäftigte sich das Projektteam mit der Suche nach vorhandenen Lösungen zur Erstellung von QC-Metriken (QC – Qualitätskontrolle) basierend auf fastq-Dateien. Die Suche konzentrierte sich auf Werkzeuge, die in C, C++ oder Rust geschrieben wurden, um die Portierung des Codes auf WebAssembly zu ermöglichen. Zudem sollte das Werkzeug nicht "roh" sein; es wurde ein bereits wissenschaftlich validierter Dienst benötigt.

Die Wahl fiel auf seqtk. Die Anwendung ist recht populär, sie ist Open Source, die Programmiersprache ist C.

Bevor man es in Wasm umwandelt, sollte man sich das Kompilierungsprinzip von seqtk für den Desktop ansehen. Laut Makefile ist Folgendes erforderlich:

# Compile to binary
$ gcc seqtk.c 
   -o seqtk 
   -O2 
   -lm 
   -lz

Im Grunde kann seqtk mit Emscripten kompiliert werden. Wenn es nicht vorhanden ist, nutzen wir Docker.

$ docker pull robertaboukhalil/emsdk:1.38.26
$ docker run -dt --name wasm-seqtk robertaboukhalil/emsdk:1.38.26

Wenn gewünscht kann man es auch selbst kompilieren, aber das braucht Zeit.

Im Container kann man problemlos emcc als Alternative zu gcc verwenden:

# Compile to WebAssembly
$ emcc seqtk.c 
    -o seqtk.js 
    -O2 
    -lm 
    -s USE_ZLIB=1 
    -s FORCE_FILESYSTEM=1

Minimale Änderungen:

Anstelle der Ausgabe in eine Binärdatei verwendet Emscripten .wasm und .js zur Generierung von Dateien, die zum Starten des WebAssembly-Moduls verwendet werden.

Um die zlib-Bibliothek zu unterstützen, wird die Flagge USE_ZLIB verwendet. Diese Bibliothek ist weit verbreitet und auf WebAssembly portiert, und Emscripten beinhaltet sie im Projekt.

Das virtuelle Dateisystem von Emscripten wird aktiviert. Es ist eine POSIX-ähnliche FS, die im Arbeitsspeicher innerhalb des Browsers funktioniert. Bei einem Seitenaktualisierung wird der Speicher gelöscht.

Um zu verstehen, warum ein virtuelles Dateisystem notwendig ist, lohnt sich ein Vergleich zwischen dem Start von seqtk über die Befehlszeile und dem Start eines kompilierten WebAssembly-Moduls.

# On the command line
$ ./seqtk fqchk data.fastq
 
# In the browser console
> Module.callMain(["fqchk", "data.fastq"])

Der Zugriff auf das virtuelle Dateisystem wird benötigt, um seqtk nicht für den zeilenweisen, sondern für den dateibasierten Input umzuschreiben. In diesem Fall wird ein Datenfragment als Datei data.fastq im virtuellen FS angezeigt, mit einem Aufruf von main() seqtk darauf.

Hier ist die neue Architektur:

Wie wir die Webanwendung mit Hilfe von WebAssembly um das 20-Fache beschleunigt haben

Die Abbildung zeigt, dass anstelle von Berechnungen im Hauptthread des Browsers WebWorkersverwendet werden. Diese Methode ermöglicht es, Berechnungen im Hintergrund durchzuführen, ohne die Reaktionsfähigkeit des Browsers zu beeinträchtigen. Der WebWorker-Controller startet einen Worker und verwaltet dessen Interaktion mit dem Hauptthread.

Der seqtk-Befehl wird durch einen Worker auf der eingehängten Datei ausgeführt. Nach Abschluss der Ausführung gibt der Worker das Ergebnis als Promise zurück. Sobald die Nachricht im Hauptthread eingegangen ist, wird das Ergebnis zur Aktualisierung der Grafiken verwendet. Und das geschieht über mehrere Iterationen.

Wie sieht es mit der Leistung von WebAssembly aus?

Um die Veränderung der Leistung zu bewerten, hat das Projektteam den Parameter der Leseoperationen pro Sekunde genutzt. Die Zeit für den Aufbau interaktiver Grafiken wird nicht berücksichtigt, da in beiden Implementierungen JavaScript verwendet wird.

Bei der Verwendung der "Out-of-the-Box"-Lösung betrug der Leistungszuwachs das Neunfache.

Wie wir die Webanwendung mit Hilfe von WebAssembly um das 20-Fache beschleunigt haben

Das ist ein hervorragendes Ergebnis, aber wie sich herausstellte, gibt es Möglichkeiten zur weiteren Optimierung. Viele der QC-Analysergebnisse verwenden nicht seqtk, daher können sie gelöscht werden. Wenn dies erfolgt, verbessert sich das Ergebnis im Vergleich zu JS auf das 13-fache.

Wie wir die Webanwendung mit Hilfe von WebAssembly um das 20-Fache beschleunigt haben

Dies wurde einfach durch das Kommentieren der printf()-Befehle erreicht.

Aber das ist noch nicht alles. Zu diesem Zeitpunkt erhält fastq.bio die Analyseergebnisse durch den Aufruf verschiedener C-Funktionen. Jede davon berechnet ihren eigenen Satz an Merkmalen, sodass jeder Dateifrag ment zweimal gelesen wurde.

Um dieses Problem zu umgehen, wurde beschlossen, zwei Funktionen in einer zu kombinieren. Infolgedessen stieg die Leistung um das 20-fache.

Wie wir die Webanwendung mit Hilfe von WebAssembly um das 20-Fache beschleunigt haben

Es ist wichtig zu beachten, dass ein solch herausragendes Ergebnis nicht immer erreicht werden kann. In einigen Fällen sinkt die Leistung, daher sollte jeder spezifische Fall bewertet werden.

Zusammenfassend lässt sich sagen, dass Wasm tatsächlich die Leistung von Anwendungen verbessern kann, aber sein Einsatz wohlüberlegt sein sollte.

Skillbox empfiehlt:

Quelle: habr.com

Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster