Arbeit mit WebAssembly und JavaScript in Node.js: fortgeschrittene Techniken

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einführung in die fortgeschrittene Arbeit mit WebAssembly und JavaScript in Node.js

\n\n

WebAssembly (Wasm) ist längst keine exotische Technologie mehr nur für Browser. Im Node.js-Ökosystem eröffnet es einzigartige Möglichkeiten zur Ausführung von hochperformanten Berechnungen, die in C/C++, Rust oder Go geschrieben sind, mit minimalem Overhead. Auf fortgeschrittenem Niveau erfordert die Arbeit mit Wasm in Node.js ein tiefes Verständnis der Speicherverwaltung, asynchroner Aufrufe und der Optimierung der Datenübertragung zwischen den Laufzeitumgebungen. In diesem Artikel analysieren wir praktische Beispiele für die Integration von WebAssembly mit JavaScript unter Verwendung von Node.js.

\n\n

1. Kompilierung und Laden von Wasm-Modulen in Node.js

\n\n

Vorbereitung der Wasm-Datei

\n

Zunächst benötigen wir ein kompiliertes Wasm-Modul. Nehmen wir an, wir haben eine einfache C-Funktion, die zwei Zahlen summiert:

\n\n
// sum.c\nint add(int a, int b) {\n    return a + b;\n}
\n\n

Kompilieren mit Emscripten oder wasm-pack:

\n
emcc sum.c -O3 -o sum.wasm --no-entry -s EXPORTED_FUNCTIONS="['_add']"
\n\n

Laden des Moduls in Node.js

\n

In Node.js können wir das Wasm-Modul auf zwei Arten laden: synchron mit readFileSync oder asynchron mit WebAssembly.instantiate. Betrachten wir die fortgeschrittene asynchrone Variante mit Importen:

\n\n
const fs = require('fs');\nconst path = require('path');\n\nasync function loadWasmModule(filePath, imports = {}) {\n    const wasmBuffer = fs.readFileSync(path.resolve(filePath));\n    const result = await WebAssembly.instantiate(wasmBuffer, imports);\n    return result.instance;\n}\n\n(async () => {\n    const instance = await loadWasmModule('./sum.wasm');\n    const { add } = instance.exports;\n    console.log('Ergebnis:', add(5, 7)); // 12\n})();
\n\n

Hier ist imports ein Objekt, das JavaScript-Funktionen enthalten kann, die von Wasm aufgerufen werden (z. B. für Logging oder Speicherarbeit).

\n\n

2. Speicherverwaltung: Arbeit mit dem linearen Speicher von Wasm

\n\n

Eine der zentralen Herausforderungen bei der fortgeschrittenen Arbeit mit Wasm ist die Verwaltung des linearen Speichers. Wasm-Module haben ihren eigenen isolierten Speicher (ArrayBuffer), auf den JavaScript direkt über instance.exports.memory zugreifen kann. Betrachten wir ein Beispiel, bei dem wir ein Zahlen-Array von JS an Wasm übergeben, es dort verarbeiten und das Ergebnis zurückerhalten.

\n\n

Beispiel: Summierung eines Arrays in C

\n
// sum_array.c\nint sum_array(int* arr, int len) {\n    int sum = 0;\n    for(int i = 0; i < len; i++) {\n        sum += arr[i];\n    }\n    return sum;\n}
\n\n

Kompilieren mit Speicherexport:

\n
emcc sum_array.c -O3 -o sum_array.wasm --no-entry \\\n  -s EXPORTED_FUNCTIONS="['_sum_array']" \\\n  -s EXPORTED_RUNTIME_METHODS="['cwrap', 'getValue']"
\n\n

JavaScript-Code zur Datenübergabe

\n
async function sumArrayWithWasm(numbers) {\n    const instance = await loadWasmModule('./sum_array.wasm');\n    const memory = instance.exports.memory;\n    const sumArray = instance.exports.sum_array;\n\n    // Speicher für das Array reservieren (4 Bytes pro int)\n    const bytesPerElement = 4;\n    const offset = instance.exports.malloc ? \n                   instance.exports.malloc(numbers.length * bytesPerElement) : \n                   0; // Wenn kein malloc vorhanden, feste Adresse verwenden\n\n    // Uint32Array zum Schreiben der Daten erstellen\n    const buffer = new Uint32Array(memory.buffer, offset, numbers.length);\n    buffer.set(numbers);\n\n    // Wasm-Funktion aufrufen\n    const result = sumArray(offset, numbers.length);\n\n    // Speicher freigeben (falls free vorhanden)\n    if (instance.exports.free) {\n        instance.exports.free(offset);\n    }\n\n    return result;\n}\n\n(async () => {\n    const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n    const sum = await sumArrayWithWasm(arr);\n    console.log('Summe des Arrays:', sum); // 55\                

Blogs

Buchempfehlungen