🌊

Web Worker+WebAssemblyのパフォーマンス計測: Rustが征く(11)

2022/02/07に公開

バンドラー使用はまた今度

関連記事:

Rustが征くシリーズ過去記事

------------------- ↓ 前書はここから ↓-------------------

前回の記事で、
WebAssembly+マルチスレッドを稼働させたので、
次はその実力が知りたい。

場面的に想像はできないが、
WebAssembly側で40億回ループさせてみる。
以前JSで測定したものと同じだ。

立て付けは前と一緒なので、
実装部分だけ記載しておく。

ヾ(・ω<)ノ" 三三三● ⅱⅲ コロコロ♪

------------------- ↓ 本題はここから ↓-------------------

メインスレッドの実装

Workerのインスタンス生成時のオプションに {type:"module"}を追加する

./dist/js/index.mjs
(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);
}
})()

importを使用して各種モジュールを読み込むように調整

./dist/js/worker.mjs
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")
})()

実装部分

WebAssembly側の実装はこんな感じかな
js側で計測すると状態がよくわからなかったので、
WebAssembly内部に計測部分を埋め込んだ。

./src/lib.rs
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");
}

ビルドしてみる

wasm-pack build --release --target web --out-dir ./dist/pkg --out-name wasm-worker

結果

(^_^;) 圧倒的やないか

JSでは40億回ループで3秒とかかかってたが、
wasmでは1/100msオーダー
比較するまでもなかったな。

実装もこれを活かした形にしなきゃならないが、
なかなか難しそうだ。

Discussion