WebAssembly: was und wie


Dieser Artikel basiert auf meinem Vortrag auf der ITSubbotnik-Konferenz am 2. November 2019 in Moskau.


Im Allgemeinen bin ich ein Backend-Programmierer, aber ich interessierte mich für diese Technologie, mit der ich mein Backend-Wissen an der Front einsetzen kann.


Das problem


Beginnen wir mit dem Problem, das durch diese (relativ neue) Technologie gelöst wird. Dieses Problem besteht darin , Code in einem Browser schnell auszuführen . Schnell - das bedeutet "schneller als JavaScript", idealerweise so schnell, wie es unser aktueller Prozessor zulässt.
Darüber hinaus ergaben sich in der Vergangenheit nach und nach wichtige zusätzliche Anforderungen für dieses Problem:


  • Keine Konfiguration - es sollte eine sofort einsatzbereite Lösung sein, nichts als ein Browser.
  • Sicher - die neue Technologie sollte keine neuen Bedrohungen hervorrufen, wir haben bereits etwas mit Sicherheit zu tun.
  • Plattformübergreifend - Browser laufen auf allen wichtigen Prozessoren, einschließlich mobiler Plattformen.
  • Praktisch für Entwickler - das ist für uns.

Geschichte vor Wasm


Wir haben viele Möglichkeiten gesehen, Code in einem Browser auszuführen. Wir können sagen, dass es auf diesem Gebiet Gewinner und Verlierer gibt.



Gewinner: Dies ist definitiv JavaScript; der V8-Motor, der JS so schnell machte; sowie HTML5.


Verlierer: ActiveX - Wenn Sie sich erinnern, war es Ihnen mit dieser Technologie im Allgemeinen möglich, alles mit dem Computer zu tun, d. H. Sicherheit war sehr schlecht; Flash - Jetzt erleben wir die Ära des Niedergangs von Flash, obwohl ActionScript in der Tat dasselbe JavaScript verwendet. Silverlight - er muss zu spät erschienen sein, um eine ernsthafte Nische zu besetzen.
Dadurch gehen alle Plugins verloren, auch aufgrund von Sicherheitsproblemen.


Es gab bereits im Browser andere Versuche, das Problem zu lösen:


  • NaCl - Native Client von Google vorgeschlagen; nativer Code direkt im Browser, der natürlich plattformübergreifend wirkt; Mozilla unterstützte diese Initiative nicht, weshalb die Implementierung nur in Chrome erfolgte.
  • PNaCl - Portable Native Client - Eine Teilmenge von LLVM IR wurde als portabler Code verwendet. wurde auch in Mozilla nicht unterstützt, wieder nur Chrome. Aus diesem Grund weigerte sich Google im Mai 2017, PNaCl zu unterstützen.

asm.js


asm.js ist eine weitere interessante Initiative der Mozilla Foundation, die uns dem Thema WebAssembly näher bringt. Es erschien im Jahr 2010 und wurde im Jahr 2013 öffentlich zugänglich.


asm.js ist eine Teilmenge von JavaScript. Mit dem Emscripten-Compiler können Sie Code aus C und C ++ kompilieren.


Da dies auch JavaScript ist, wird dieser Code in jedem Browser ausgeführt. Darüber hinaus konnten die wichtigsten modernen Browser asm.js seit langem schnell erkennen und effizient in den systemeigenen Code des Prozessors kompilieren. Im Vergleich zum nativen Code, der direkt von C / C ++ erhalten wird, ist der Code, der von asm.js erhalten wird, nur um das 1,5-2-fache langsamer (50-67%).



Links steht der Code der einfachsten Funktion in C / C ++, rechts wird angezeigt, was sich nach dem Kompilieren in asm.js verwandelt. Erstens sehen wir hier die Zeile 'use asm' , dies ist eine Markierung, die deutlich macht, dass der Code für asm.js als nächstes verwendet wird. Und in diesem Code sehen wir Konstruktionen der Form |0 , dies ist eine bitweise ODER-Operation mit einem Nullwert. Gemäß der Spezifikation ist das Ergebnis dieser Operation eine 32-Bit-Ganzzahl mit Vorzeichen. Aber dieser Typ ist nicht einmal in JavaScript. Dieser Typ entsteht jedoch als Ergebnis dieser Operation, d.h. Es ist im Wesentlichen eine Besetzung für einen bestimmten Typ.


Asm.js basiert im Allgemeinen auf unserem Wissen darüber, wie die Browser-Engine JS kompiliert, um diese Arbeit zu optimieren.


Was ist WebAssembly?



WebAssembly (oder Wasm ) ist ein Binärformat, das in einem Browser, einer virtuellen Maschine und dem Ergebnis der Kompilierung aus einer höheren Sprache ausgeführt wird.


Wasm ist keine Programmiersprache, so wie Java-Bytecode keine Programmiersprache ist, sondern ein Kompilierungsergebnis und ein laufender Codeblock.


Jemand, der sehr schlau war, sagte, dass der Name Webassembly (also „Assembler für das Web“) völlig falsch ist, da es sich nicht um Assembler (keine Programmiersprache) handelt und nichts mit dem Web zu tun hat (da es sich nur um eine virtuelle Maschine handelt).


Die Entwickler von WebAssembly haben sich von den folgenden Zielen und Einschränkungen leiten lassen - siehe das Video Die Entwicklung von Wasm zu einer richtigen Fehlbezeichnung: Andreas Rossberg .



Tatsächlich kommt es auf drei Dinge an: plattformübergreifend, kompakt und schnell. Es gab jedoch noch eine weitere wichtige Anforderung, nämlich "Verkaufsfähigkeit" - die Entwickler der wichtigsten Browser hätten die Initiative ergreifen und ergreifen sollen. Infolgedessen konnten Vertreter von Google, Mozilla, Microsoft und Apple an der Entwicklung der Spezifikation "verkauft" werden.


Mal sehen, wie Wasm einer virtuellen Maschine ähnelt.



Dies ist ein solcher "fiktiver Prozessor", aber ohne Register wird alles über den Stack erledigt. Nur vier Datentypen: zwei Integer, zwei Floating. Relativ einfache Bedienung - siehe Spezifikation und interaktive Tabelle .



Flaches Speichermodell: Für den Speicher wird ein einzelner Block zugewiesen, dessen Größe ein Vielfaches von 64 KB ist. Hier sind der Code, die Daten, die Konstanten, die globalen Variablen, der herabwachsende Stapel und der heranwachsende Haufen. Sie können den Heap bei Bedarf automatisch vergrößern lassen, während der Speicherblock um ein Vielfaches von 64 KB erweitert wird.


Zeiger werden nicht verwendet (dies dient der Sicherheit), stattdessen wird ein Index verwendet. Der Index ist 32-Bit und adressiert somit bis zu 4 GB Arbeitsspeicher.


Auf den gesamten WebAssembly-Speicher kann sowohl zum Lesen als auch zum Schreiben vollständig mit JavaScript zugegriffen werden.



Werfen wir einen Blick auf das WebAssembly-Laufzeitmodell. Wasm wird immer NUR von JavaScript geladen und aufgerufen. Darüber hinaus arbeiten JS und Wasm in derselben Sandbox und werden von derselben Engine ausgeführt.


Beachten Sie, dass Sie JS auch von Wasm aus aufrufen können. Es kann ein Funktionsaufruf mit Übergabe von Argumenten und Rückgabe eines Wertes sein oder es kann einfach eine beliebige Zeichenfolge als JS-Code ausgeführt werden.


WebAssembly testen


Um mit WebAssembly zu beginnen, empfehle ich die Verwendung der WasmFiddle- Website oder von WebAssembly Studio - auf einfache und visuelle Weise können Sie selbst nachvollziehen, was Wasm wirklich ist.



Hier befindet sich der Quellcode in C / C ++ oben links (in diesem Fall die rekursive Funktion zur Berechnung der Fibonacci-Zahl), oben rechts der JS-Code zum Laden von Wasm, zum Instanziieren des Wasm-Moduls und zum Aufrufen der fib() -Funktion. Wenn wir den Build-Button drücken, erhalten wir einen Wasm-Codeblock (.wasm-Datei), den wir jederzeit zu einer Textdarstellung (.wat-Datei) erweitern können.


Diese Textdarstellung mit einer Reihe von Klammern ist im Wesentlichen ein abstrakter Syntaxbaum (AST). Nun, eigentlich mit einer Klammer, ähnelt es der Lisp-Sprache. Theoretisch können wir den Code als Textdarstellung bearbeiten und dann wieder in ein Binärformat komprimieren - dies erinnert an Assembler-Programmierung. Aber normalerweise erhalten wir binären Wasm als Ergebnis der Kompilierung aus einer Hochsprache.


2017: Produktionsbereit


Im November 2017 wurde WebAssembly als "einsatzbereit für die Produktion" deklariert. Die Spezifikation für alle Hauptteile von Wasm wurde vorbereitet, die Implementierung von Wasm wurde in allen gängigen Browsern veröffentlicht. Daher wurde für WebAssembly MVP veröffentlicht - Minimum Viable Product, Version 1.0, mit der wir uns jetzt befassen.


Browser-Unterstützung


Ende 2017 wurden Releases aller gängigen Browser mit WebAssembly-Unterstützung veröffentlicht:



Die Ausnahme ist IE11, es gibt keine Unterstützung dafür und höchstwahrscheinlich wird es weg sein. Es wurde angenommen, dass es für ältere Browser eine Polyfüllung geben wird - die Fähigkeit, Wasm in asm.js zu konvertieren; Es gibt solche Prototypen, aber meines Erachtens werden diese Projekte aufgegeben, anscheinend ist die Community nicht in der Lage, sie umzusetzen.


Von allen installierten Browsern unterstützen nun ~ 88% Wasm .



Sprachunterstützung


Damit Ihre Lieblingssprache in Wasm kompiliert werden kann, muss der Compiler dieses Kompilierungsziel bereitstellen. Mittlerweile unterstützen einige Sprachen Wasm, und es gibt jeden Monat mehr von ihnen. Siehe appcypher / awesome-wasm-langs .


  • C / C ++ - durch Emscripten sehr gute Unterstützung.
  • Rust - Wasm Support erschien vor langer Zeit, das Ökosystem rund um Wasm ist weitgehend auf Rust aufgebaut.
  • Java - durch TeaVM, JWebAssembly, Bytecoder - auf experimenteller Ebene.
  • Kotlin - Es gibt Unterstützung in Kotlin / Native über das LLVM-Backend - Experimental.
  • Geh
  • Über Blazor (Mono) und in Zukunft auf Uno Platform .
  • TypeScript - durch AssemblyScript .

Vor nicht allzu langer Zeit gab es Neuigkeiten, dass LLVM nun Wasm als Kompilierungsziel unterstützt. Dadurch können Entwickler von Programmiersprachen noch mehr Sprachen in Wasm kompilieren.


Anwendungsfälle


Dies ist wahrscheinlich eine der Hauptfragen: "Wie kann ich Wasm verwenden?"


WebAssembly verwendet bereits aktiv:


  • Spiele, Spiele-Engines, Physik-Engines, VR / AR - zum Beispiel Godot , Doom 3
  • Emulatoren, virtuelle Maschinen - zum Beispiel DOSBox
  • Grafik- / 3D-Editoren - Figma , AutoCAD
  • Web-Kunden für Finanzhandelsplattformen - Ich habe Präsentationen über zwei solche Kunden gesehen
  • Codecs und Audio- / Videofilter - z. B. ffmpeg
  • Datenbanken - beispielsweise SQLite

Andere mögliche Szenarien:


  • Progressive Webanwendungen (PWA)
  • Erkennung durch ein trainiertes neuronales Netzwerk

Leistung


Wasm-Leistung war einer der wichtigsten Verkaufsfaktoren, aber was passiert wirklich?


Im Vergleich zu JavaScript stellt sich heraus, dass Wasm im Durchschnitt schneller ist. In jedem Fall müssen Sie jedoch einen JS / Wasm-Vergleich durchführen, da sich herausstellen kann, dass es um ein Vielfaches besser und um ein Vielfaches schlechter ist. Dies kann auch stark vom verwendeten Browser abhängen.


Tatsächlich ist die Spitzenleistung von JS und Wasm gleich, da beide zu nativem Prozessorcode werden. Aber JS ist viel einfacher in der Leistung zu verlieren, und Wasm bietet einen "gleichmäßigeren" Ansatz.


Wasm schneidet im Volumetric Computing in der Regel gut ab. Wo es viele Speicheroperationen gibt, verliert Wasm. Nun, das Hauptproblem in realen Anwendungen ist das langsame JS <-> Wasm-Interop. Siehe zum Beispiel einen Benchmark .



Im Juli 2019 erschien der wissenschaftliche Artikel „Nicht so schnell: Analyse der Leistung von WebAssembly vs. Nativer Code . " Die Autoren implementierten die Möglichkeit, Linux-Konsolendienstprogramme unter WebAssembly auszuführen, um Benchmarks auszuführen, und verwendeten SPEC-Benchmarks, um die Wasm-Leistung im Vergleich zu denselben Tests auf asm.js und nativem Code zu bewerten.


Die Ergebnisse sind wie folgt:


  • Wasm 30% schneller als JavaScript (Durchschnitt für diese Tests)
  • Wasm ist 50% langsamer als der native Code (im Durchschnitt in diesen Tests)

Die Autoren des Artikels gaben auch eine Analyse der Gründe, aus denen Wasm „langsamer wird“:


  • ungefähr doppelt so viele Datenlade- / Speichervorgänge im Vergleich zum nativen Code;
  • mehr Verzweigungen - verursacht durch die Notwendigkeit zusätzlicher Überprüfungen beim Zugriff auf den Speicher;
  • mehr verfehlt den L1-Cache.

Im Allgemeinen ist die Leistung gar nicht so schlecht. Darüber hinaus können Browser-Entwickler mit dieser Analyse Wasm noch schneller machen.


In Zukunft wird Wem nicht nur durch eine bessere Optimierung der Browser beschleunigt, sondern auch durch neue Funktionen, wie z. B .: Blockieren von Speicheroperationen, Unterstützung für SIMD-Anweisungen, Unterstützung für Threads.


Was wird als nächstes passieren?


Wie entwickelt sich WebAssembly?


Zunächst setzt das Spezifikationsteam für Wasm seine Arbeit fort. Die Spezifikationen befinden sich in verschiedenen Stadien (Phasen), für diese Arbeit gibt es eine bestimmte „Roadmap“ .


Insbesondere erwarten wir in naher Zukunft weitere Merkmale dieser Art:


  • Float-to-Int-Konvertierungen ohne Trapping - Die Konvertierung von einem Floating-Wert in eine Ganzzahl kann nun unter bestimmten Bedingungen eine Ausnahme verursachen. Für einen Programmierer ist dies ziemlich unerwartet, daher müssen alle derartigen Konvertierungen umbrochen werden, was die Leistung beeinträchtigt. Diese Funktion löst das Problem.
  • Mehrfachwert - die Fähigkeit, mehr als einen Wert von einer Funktion zurückzugeben, die Fähigkeit, neue Anweisungen zu erstellen, die mehr als einen Wert zurückgeben - zum Beispiel das Ergebnis der Division und den Rest der Division oder das Ergebnis der Addition und des Übertragsbits.
  • Reference Types ist eine Einführung in den anyref-Typ und bedeutet "Verknüpfung zu etwas auf dem JS-Heap", der erste Schritt zur Beschleunigung der Interaktion mit JS.

Zweitens implementieren Browserentwickler ihrerseits diese Spezifikationen, d.h. Allmählich werden neue Funktionen zu Wasm hinzugefügt, die zuerst in den Einstellungen unter der Flagge verborgen und dann standardmäßig aktiviert werden.


Im Folgenden finden Sie beispielsweise eine Liste der Chrome-Funktionen im Zusammenhang mit WebAssembly .
Für Firefox finden Sie hier eine ähnliche Liste.


WebAssembly außerhalb des Browsers


Wie oben erwähnt, ist Wasm im Wesentlichen nicht mit dem Web verbunden, sondern lediglich eine virtuelle Maschine. Dies bedeutet, dass es auch außerhalb des Webs verwendet werden kann.


Jetzt gibt es verschiedene Szenarien für die Verwendung von Wasm außerhalb des Browsers:


  • Node.js - Node.js basiert auf der V8-Engine, die Wasm unterstützt.
  • Eine separate Konsolenanwendung, Anwendungscode, wird in Wasm VM ausgeführt - Beispiele für eine solche Laufzeit: wasmtime , wasmer.
  • Wasm VM wird als Bibliothek aus anderen Sprachen verwendet. Mit wasmer können Sie sich beispielsweise aus einem Dutzend verschiedener Sprachen aufrufen.

Für Wasm, das außerhalb des Browsers arbeitet, werden die Sandbox-Einschränkungen nicht mehr benötigt, im Gegenteil, der Zugriff auf die Systemfunktionen ist erforderlich - das Dateisystem und die Dateien, die Konsolen-E / A usw. Dies führte zur Erstellung des WebAssembly System Interface (WASI), einer plattformübergreifenden API-Spezifikation ähnlich POSIX. Siehe WebAssembly / WASI und wasi.dev .



Der nächste Schritt war das Erstellen eines Paketmanagers - Wasm Package Manager (WAPM) - wapm.io. Hier können Sie die fertige .wasm-Datei nehmen und in Ihrer Anwendung verwenden. Normalerweise sprechen wir über Wasm-Versionen einiger bekannter Bibliotheken. Einige Pakete sind mit dem WASI-Tag versehen, was bedeutet, dass sie nur in Szenarien außerhalb des Browsers verwendet werden können.


Fazit


Die Verwendung von WebAssembly ist also durchaus möglich, da es seit zwei Jahren „produktionsbereit“ ist.
Die Verwendung von Wasm kann im Vergleich zu ähnlichem JavaScript-Code durchaus zu einer Beschleunigung führen, Sie sollten jedoch immer prüfen, ob Sie eine Beschleunigung erhalten.
Die Wasm-Unterstützung von Programmiersprachen wird ständig weiterentwickelt.


Nun, und das Wichtigste ist, dass WebAssembly die Landschaft des Webs etwas „verändert“ hat - es hat uns neue Nutzungsszenarien geliefert, die wir in unseren Anwendungen implementieren können.


Referenzen



Tolle Angebote:



Video:


Source: https://habr.com/ru/post/de475778/


All Articles