Webassemblyマルチスレッドクレート:wasm-futures-executorを試す
エラーがでないだけでありがたい
関連記事:
- Webassemblyマルチスレッドクレート:wasm-mtを試す
- rollup.jsに爆速esbuildを組み込む方法
- Rustのimage::load_from_memory遅すぎ問題
- WSL2で作るWindows開発環境: Rustが征く(1)
Rustが征くシリーズ過去記事
------------------- ↓ 前書はここから ↓-------------------
Webassemblyマルチスレッド用crateを調べる: Rustが征く(7)で紹介した三つのモジュール
を考察してみたが、
考察、記事化してる最中に新しいモジュールが出ていた。
ついでだからこれも試してみようと思う。
Rustの最新バージョンではビルドできなかったので、
ビルドできたバージョンで実行している。
コンパイル条件は
設定項目 | 設定値 |
---|---|
toolchain | nightly-2021-12-02 |
build.target | wasm32-unknown-unknown |
build.rustflags | ["-C", "target-feature=+atomics,+bulk-memory"] |
unstable.build-std | ["panic_abort", "std"] |
wasm-pack target | web |
ヾ(・ω<)ノ" 三三三● ⅱⅲ コロコロ♪
------------------- ↓ 本題はここから ↓-------------------
プロジェクト作成
wasm-pack new wasm-executor
cd wasm-executor
cargo install cargo-edit wasm-pack wasm-bindgen-cli
cargo install cargo-generate --version 0.6.1
cargo upgrade
cargo add futures js-sys wasm-bindgen-futures anyhow
cargo add wasm-futures-executor --git https://github.com/wngr/wasm-futures-executor
ビルドの各種設定
ツールチェインの設定
rustup toolchain add nightly-2021-12-02
rustup component add rust-src --toolchain nightly-2021-12-02
printf '[toolchain]\nchannel = "nightly-2021-12-02"' | tee ./rust-toolchain.toml
rustup toolchain list
stable-x86_64-unknown-linux-gnu (default)
nightly-2021-12-02-x86_64-unknown-linux-gnu (override)
ビルドオプションの設定
[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 config get -Z unstable-options
build.target = "wasm32-unknown-unknown"
target.wasm32-unknown-unknown.rustflags = ["-C", "target-feature=+atomics,+bulk-memory,+mutable-globals"]
unstable.build-std = ["panic_abort", "std"]
実装
パッケージが配布しているサンプルを使って実装してみる。
mod utils;
use futures::channel::mpsc;
use futures::StreamExt;
use js_sys::Promise;
use wasm_bindgen::prelude::*;
use wasm_futures_executor::ThreadPool;
#[wasm_bindgen]
pub async fn start() -> Result<JsValue, JsValue> {
let pool = ThreadPool::max_threads().await?;
let (tx, mut rx) = mpsc::channel(10);
for i in 0..20 {
let mut tx_c = tx.clone();
pool.spawn_ok(async move {
tx_c.start_send(i * i).unwrap();
});
}
drop(tx);
let mut i = 0;
while let Some(x) = rx.next().await {
i += x;
}
Ok(i.into())
}
ビルド
wasm-pack build --release --target web -d ./dist/pkg
フロントエンド側の準備
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="./js/main.mjs"></script>
</head>
<body>
</body>
</html>
import init, { start } from '/pkg/wasm_executor.js';
(async () => {
await init();
const res = await start();
console.log("result", res);
})()
サーバーファイルを設置
WebAssemblyのMIMETypeとクロスオリジン問題を考慮して、
expressで頑張る系のサーバーファイルを用意
const express = require('express')
const app = express()
const port = 3000
express.static.mime.define({'application/wasm': ['wasm']})
app.use(express.static('./dist', {
setHeaders: (res) => {
res.set('Cross-Origin-Opener-Policy', 'same-origin');
res.set('Cross-Origin-Embedder-Policy', 'require-corp');
}
}));
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
スレッド数指定はできないのか。
そこはクライアント依存になりそう。
結果
(^_^)b いけてる
動くだけでもありがてー
右側のworkerが子スレッド。
上限の8スレッドが立って別々に計算している。
------------------- ↓ 後書はここから ↓-------------------
Rustで普通にスレッドを使うように実装できるのはいいね。
wasm-bindgen-rayonやwasm_threadをリスペクトしてるらしいので、
そのあたりを意識した結果の実装なのかなと。
ビルドターゲットがwebなので、
バンドラーとの相性はいいかもしれない。
wasm-mtに比べて更新頻度が全くなく、
令和3年8月頃にリリースしてから全く動きがない。
こういうのは使うの躊躇するなぁ。
また、行進促すためのスナイプブログ書こうかしら。
最新のRustではビルドできなかったので、
そのあたりの対応をして欲しいところ。
Discussion