Webassemblyマルチスレッドクレート:wasm-bindgen-rayonを試す

2021/10/27に公開
1

なお。。。

関連記事:

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

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

WebWokerとWebAssemblyの挙動が大分つかめた。
次は動かないモジュールを動かし考察していく。

Webassemblyマルチスレッド用crateを調べる: Rustが征く(7)で紹介した三つのモジュール

これらをなんとか動かして考察していく。
まずはwasm-bindgen-rayonから。

コンパイル条件は

設定項目 設定値
toolchain nightly-2021-07-29
build.target wasm32-unknown-unknown
build.rustflags ["-C", "target-feature=+atomics,+bulk-memory"]
unstable.build-std ["panic_abort", "std"]
pasm-pack target web

この会ではインストールなどの説明は全部省くので、
サンプルなどを目当てに来られた方には申し訳ない。
(シリーズに加えてないのはそれが理由)

フロントエンド側はvanillaJS(素のJavaScriptのこと)で実装。
要素が増えると動かすまでに余計な手間が増えるからね。

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

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

プロジェクト作成

wasm-pack new wasm-rayon
cd wasm-rayon
cargo install cargo-edit wasm-pack wasm-bindgen-cli
cargo upgrade
cargo add rayon
cargo add wasm-bindgen-rayon --features "no-bundler"

ビルドの各種設定

ツールチェインの設定

rustup toolchain add nightly-2021-07-29
rustup component add rust-src --toolchain nightly-2021-07-29
printf '[toolchain]\nchannel = "nightly-2021-07-29"' | tee ./rust-toolchain.toml
rustup toolchain list
  stable-x86_64-unknown-linux-gnu (default)
  nightly-2021-07-29-x86_64-unknown-linux-gnu (override)

ビルドオプションの設定

./.cargo/config.toml
[build]
target = "wasm32-unknown-unknown"

[target.wasm32-unknown-unknown]
rustflags = ["-C", "target-feature=+atomics,+bulk-memory,+mutable-globals"]

[unstable]
build-std = ["panic_abort", "std"]

チェック

cargo check
wasm-pack build --release --target web -d ./dist/pkg

実装

./src/lib.rs
pub use wasm_bindgen_rayon::init_thread_pool;
use rayon::prelude::*;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn sum_numbers(numbers: &[i32]) -> i32 {
    numbers.par_iter().sum()
}

フロントエンド側の準備

./dist/js/main.mjs
import init, {initThreadPool, sum_numbers} from "/pkg/wasm_rayon.js";

(async() => {
    await init();
    await initThreadPool(navigator.hardwareConcurrency);

    console.log(sum_numbers(new Int32Array([3,5,6])));
})()
./dist/index.html
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
    <title>My awesome Rust, WebAssembly, and Parcel application</title>
    <script type="module" src="./js/main.mjs"></script>
  </head>
  <body>
  </body>
</html>

結果

\(^o^)/オワタ

はいはい解散

Discussion

かめのこにょこにょこかめのこにょこにょこ

手元の環境でも同様のエラーが出ました。
デバッグ情報と該当する関数をみたところ、原因は次のように推定されました。

  • スレッドプール上のスレッドが全てアクティブになるのを待つために、WebAssembly 命令 Atomics.wait を使っている
  • メインスレッド上ではスレッドをブロックする命令を使ってはならない

いずれにせよ、wasm-bindgen-rayon の対応を待つしかないでしょう。

メインスレッド上で使うこと自体、サポートされていないと考えた方が妥当かもしれません。