iTranslated by AI
Benchmarking Web Worker + WebAssembly: The Rust Journey (11)
Bundler, Maybe Next Time
Related Articles:
- How to integrate lightning-fast esbuild into rollup.js
- The problem of Rust's image::load_from_memory being too slow
Previous articles in the 'Rust Journey' series
- Windows development environment with WSL2: Rust Journey (1)
- Knocking on the door of WebAssembly with wasmer: Rust Journey (2)
- Calling WebAssembly functions from JavaScript: Rust Journey (3)
- Running WebAssembly with TypeScript and Rollup: Rust Journey (4)
- Svelte, WebAssembly, TypeScript, and Rollup: Rust Journey (5)
- Isn't the WASM size too big?: Rust Journey (6)
- Exploring crates for WebAssembly multi-threading: Rust Journey (7)
- Sleep in WebAssembly: Rust Journey (8)
- Multi-threading with Web Workers (JS only): Rust Journey (9)
- Multi-threading with Web Workers + WebAssembly: Rust Journey (10) ← Current article
------------------- ↓ Preface starts here ↓-------------------
In the previous article,
I got WebAssembly + multi-threading running,
so now I want to know its true capabilities.
While I can't imagine a specific real-world scenario,
I'll try running a 4-billion-iteration loop on the WebAssembly side.
This is the same test I performed with JS previously.
Since the setup is the same as before,
I will only include the implementation details.
ヾ(・ω<)ノ" 三三三● ⅱⅲ Roll, roll♪
------------------- ↓ Main content starts here ↓-------------------
Main Thread Implementation
Add {type:"module"} to the options when creating the Worker instance.
(async () => {
const maxWorkers = navigator.hardwareConcurrency || 4;
const workers = []
const path = new URL('/js/worker.mjs', import.meta.url)
for (let i = 0; i < maxWorkers; i++) {
workers[i] = new Worker(path, {type:"module"})
workers[i].addEventListener('message', (event) => {
console.log("Data from worker"+i+" received: ", event.data);
}, false);
}
})()
Adjusted to load various modules using import.
import wasm_bindgen, {loop_wasm} from "/pkg/wasm-worker.js"
(async () => {
const path = new URL("/pkg/wasm-worker_bg.wasm", import.meta.url)
await wasm_bindgen(path)
console.time("sleep")
loop_wasm()
console.timeEnd("sleep")
})()
Implementation Details
Here is what the WebAssembly side implementation looks like.
Since I couldn't get a clear picture of the state when measuring from the JS side,
I embedded the measurement code directly inside WebAssembly.
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
pub fn log(message: String);
#[wasm_bindgen(js_namespace = console)]
pub fn time(index: &str);
#[wasm_bindgen(js_namespace = console)]
pub fn timeEnd(index: &str);
}
#[wasm_bindgen]
pub fn loop_wasm() {
let max: u32 = 40_0000_0000;
time("wasm");
for i in 0..max {}
timeEnd("wasm");
}
Building the project:
wasm-pack build --release --target web --out-dir ./dist/pkg --out-name wasm-worker
Results

(^_^;) That's overwhelming.
In JS, a 4-billion-iteration loop took about 3 seconds,
but in WASM, it was in the 1/100ms order.
There was no point in even comparing them.
I need to come up with an implementation that leverages this,
but it seems quite difficult.
completed
Discussion