Multi-Threading dengan Wasm
WebAssembly mendukung shared memory dan threads melalui SharedArrayBuffer dan Web Workers. Ini memungkinkan parallel computation untuk workload berat seperti ray tracing, video encoding, atau physics simulation.
Prerequisites
// SharedArrayBuffer butuh Cross-Origin Isolation headers:
// Server harus kirim:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
// Cek di browser:
console.log(crossOriginIsolated); // harus true
console.log(typeof SharedArrayBuffer); // "function"
SharedArrayBuffer Basics
// Buat shared memory (bisa diakses dari multiple workers)
const sharedBuffer = new SharedArrayBuffer(1024); // 1KB shared
const view = new Int32Array(sharedBuffer);
// Main thread
view[0] = 42;
// Kirim ke worker (zero-copy! tidak di-clone)
worker.postMessage({ buffer: sharedBuffer });
// Worker bisa baca/tulis ke memory yang sama
// tanpa overhead serialization/deserialization
Atomics: Thread-Safe Operations
const shared = new SharedArrayBuffer(4);
const view = new Int32Array(shared);
// Thread-safe operations
Atomics.store(view, 0, 100); // atomic write
const val = Atomics.load(view, 0); // atomic read: 100
Atomics.add(view, 0, 5); // atomic add: 105
Atomics.sub(view, 0, 3); // atomic sub: 102
// Compare and swap (CAS)
Atomics.compareExchange(view, 0, 102, 200);
// Jika view[0] == 102, set ke 200
// Wait / Notify (mutex-like)
// Worker:
Atomics.wait(view, 0, 0); // block sampai notify
// Main:
Atomics.notify(view, 0, 1); // bangunkan 1 waiter
Wasm Threads (Rust)
// Cargo.toml
[dependencies]
wasm-bindgen = "0.2"
rayon = "1"
wasm-bindgen-rayon = "1"
// Build flags
// .cargo/config.toml
[target.wasm32-unknown-unknown]
rustflags = ["-C", "target-feature=+atomics,+bulk-memory,+mutable-globals"]
use rayon::prelude::*;
use wasm_bindgen::prelude::*;
// Initialize thread pool
#[wasm_bindgen]
pub fn init_threads(num_threads: usize) -> Result<(), JsValue> {
wasm_bindgen_rayon::init_thread_pool(num_threads)
}
// Parallel computation
#[wasm_bindgen]
pub fn parallel_sum(data: &[f64]) -> f64 {
data.par_iter().sum()
}
// Parallel image processing
#[wasm_bindgen]
pub fn parallel_grayscale(pixels: &mut [u8]) {
pixels.par_chunks_mut(4).for_each(|pixel| {
let gray = (0.299 * pixel[0] as f32
+ 0.587 * pixel[1] as f32
+ 0.114 * pixel[2] as f32) as u8;
pixel[0] = gray;
pixel[1] = gray;
pixel[2] = gray;
});
}
Tips
- COOP/COEP headers wajib — Tanpa ini, SharedArrayBuffer tidak tersedia
- Thread count — Gunakan
navigator.hardwareConcurrencyuntuk jumlah optimal - Overhead — Jangan spawn thread untuk task kecil. Overhead context switch bisa lebih besar dari benefit
- Debugging — Race condition sangat sulit di-debug. Pakai Atomics dengan benar