Begriff
Threads in Wasm
Warum wichtig?
Dieser Begriff ist ein Knoten im SengakujiWorks-Wissensnetz. Nutze Level 0 für die erste Einordnung, Level 1 für Praxis, Level 2 für technische Struktur und Level 3 für Grenzen, Fallstricke und Expertenkontext.
JavaScript ist Single-Threaded. (Es gibt Web Workers, aber die können keinen Speicher teilen - sie müssen Daten kopieren/klonen).
Echte Native Apps (C++/Rust) nutzen Shared Memory Threads.
Threads in Wasm erlaubt genau das im Browser.
Du startest mehrere Web Workers.
Aber alle Workers greifen auf denselben SharedArrayBuffer (den Wasm Memory) zu.
Sie nutzen Atomics (native CPU-Instruktionen), um sich zu synchronisieren, ohne Daten zu kopieren.
Das erlaubt es, Photoshop oder High-End Games fast 1:1 in den Browser zu portieren.
Merksatz: Eine WebAssembly-Funktionalität, die echten Multithreading-Support durch gemeinsam genutzten Speicher (SharedArrayBuffer) und atomare Operationen ermöglicht, ähnlich wie bei nativen Desktop-Anwendungen.
- Compiler Flags: In Emscripten
-pthread. In Rusttarget-feature=+atomics. - Header: Der Webserver muss spezielle Security-Header senden (
Cross-Origin-Opener-Policy: same-origin,Cross-Origin-Embedder-Policy: require-corp). Ohne diese Header erlaubt der Browser keinenSharedArrayBuffer(wegen Spectre-Angriffen).
1. wait und notify
Wasm führt memory.atomic.wait32 und memory.atomic.notify ein.
Das entspricht den Futexes in Linux.
Ein Thread kann schlafen ("Warte, bis an Adresse X der Wert 0 steht"), ohne CPU zu verbrennen.
Das ist die Basis für Mutexes und Condition Variables.
2. Kein thread.spawn
Wasm selbst kann (noch) keine Threads erzeugen. Das JavaScript (der Host) muss die Web Workers starten und das Wasm-Modul instanziieren. Das Wasm-Modul weiß dann: "Ah, ich bin Thread Nr. 4."
1. C++11 Memory Model im Browser
Wasm Threads mappen direkt auf das C++11/C11 Speicher-Modell.
Wenn du in Rust AtomicOrder::SeqCst nutzt, sorgt Wasm dafür, dass die CPU (und der Browser) die richtigen Memory Barriers (Zäune) setzen.
Das ist extrem heikel: Ein Fehler in der Wasm-Engine könnte dazu führen, dass Code auf Intel (starkes Speichermodell) funktioniert, aber auf ARM (schwaches Speichermodell) abstürzt. Browser-Entwickler verbringen Monate damit, diese "fences" für jede CPU-Architektur korrekt in JIT-Code zu übersetzen.
2. Shared Worklets (Audio)
Ein spezieller Fall sind AudioWorklets.
Hier darf es niemals Ruckler geben. Wasm Threads erlauben es, Audio-Daten in einem High-Priority Thread zu berechnen, während das UI in einem anderen Thread läuft. Über den SharedArrayBuffer tauschen sie Samples aus. Das macht professionelle Musiksoftware (DAWs) im Browser erst möglich, die früher an der Latenz von JavaScript gescheitert wäre.
3. Proxying to Main Thread
Da Web Workers (und damit Wasm Threads) keinen Zugriff auf das DOM (document, window) haben, müssen sie Anfragen an den Main Thread schicken (Proxying).
In der Produktion nutzt man oft Bibliotheken wie Comlink oder spezielle Emscripten-Wrapper, die System-Calls (wie glDrawArrays) automatisch vom Worker zum UI-Thread tunneln. Das kostet Latenz. Experten minimieren diesen "Boundary-Crossing"-Overhead, indem sie so viel Logik wie möglich rein im Wasm-Space (Shared Memory) lassen.
Quick-Check
Warum Spectre-Header?
Mit einem exakten Shared Timer (den man mit Threads bauen kann) könnte man Cross-Origin Daten aus dem Speicher lesen (Side Channel). Die Header isolieren die Webseite in einen eigenen Prozess, damit sie niemanden ausspionieren kann.Blockiert der Main Thread?
Wasm verbietetatomic.waitim Main Thread (UI Thread). Sonst würde der Browser einfrieren. Threads müssen im Worker laufen.Garbage Collection und Threads?
Noch schwierig. WasmGC Objekte zwischen Threads zu teilen ist komplizierter als lineares Memory. Daran wird gearbeitet ("Shared-Everything").