見出し画像

Worker → WASM / WASM → Worker

こんにちは、株式会社LabBase(旧POL)でエンジニアをしているミズノです。今年も12月に入り、アドベントカレンダーの季節になりました。もちろん今年も参加します。多数のエンジニアが投稿するので、LabBaseの開発組織の雰囲気が見えてくると思います。25日間毎日投稿されるので、ご期待ください。(おそらく!)
初回は私が担当です。

株式会社LabBaseのアドベントカレンダーはこちら

最近試している事

直近でWeb WorkerとWASMに触れる機会があり、その辺りで試している事を紹介したいと思います。

弊社の開発にではRustを採用していますが、その流れでWASMを試しています。例えば以下のようなもの。

  • データの圧縮処理

  • 検索処理

両方とも処理速度を求めがちで、これらをフロントや、エッジなどで動かせると良い体験に繋がりそうだなと考えています。
僕はWeb WorkerとWASMの組み合わせを試してます。

Web Worker + WASM

Web Workerはご存知の通りブラウザ上にプロセスっぽいスレッドのようなものを作ることができる機能です。割と両方の要素を持ったユニークな機能です。

WASMの処理は大概重いのを任せるので、ブラウザで動かす場合メインスレッド(わかりやすいので便宜上そう呼んでます)で実行されると処理速度が早いとはいえ、負負荷が厳しくなります。
そこでWeb Workerを用意し、別のスレッドに任せると良さそうです。実際CPU割り当てているのかの情報までは掴めてません。(コア数増えるとパフォーマンスあがったよという論文は見かけました)

WASMの準備

今回はwasm-packを利用して開発しています。まずは簡単なWASMコードを準備します。最初はWASM側でコンソールログを吐けるようにします。

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);
}

#[wasm_bindgen]
pub fn console_log(message: &str) {
   log(message)
}

wasm_bindgen使うとこんな感じで簡単にConsole .logを利用できるのでおすすめです。一度これでビルドします。

$ wasm-pack build --target web

これで/pkgディレクトリに、ファイルが作られます。

Workerの準備

pkgディレクトリ内の.jsファイルをimportします。初期化のためのinit関数が作れるので、initを実行後に今回作成したconsole_log関数を実行します。

import init, {console_log} from "../pkg/test_wasm";
const ctx = self as any;
(async () => {
    await init();
    console_log("hello from worker")
})();

こんな感じでWorker内でWasmコードの実行は問題なくできました。ここでWasm→Workerはできるのかなと気になったので試します。

WASM→Worker

WASMからWorkerを実行を試してみます。web_sysのクレートの中覗くとfeatureでWorkerがあるので、それを使えばいけそうです。
post_messageのパラメータがJsValueとして扱うのが少しめんどくさいですね。
どうやらWASMからブラウザ側へのやりとりはJsValueになるっぽいですね。

WASMからのWorker呼び出し

#[wasm_bindgen]
pub fn worker_run(path: &str) -> Result<(), JsValue>  {
    let worker = web_sys::Worker::new(path)?;

    let msg = JsValue::from_str("Hello from wasm");
    worker.post_message(&msg)
}

featuresの設定

web_sys::Workerはfeatureなので、Cargo.tomlにも指定が必要です。

[dependencies]
web-sys = { version="0.3.60", features=["Worker"] }

Worker.jsは簡単にConsole.logで出力するだけで試してます。

const ctx = self;
(async () => { 
    ctx.addEventListener('message',(e) => {
        console.log(e.data);
    }, false);
})();

実行するとログの出力が確認できました。

まとめ

  1. Wasm → Worker

  2. Worker → Wasm

どちらも動作が確認できました。
割とすんなり試せるので、WASMの利用は気軽に試せるところまで来てるんだなと確認できたのがよかったです。

こんな感じで業務で使うことが決まった技術だけでなく、新しい技術も積極的に試すのがLabBaseのエンジニア組織の面白いところかもしれません。
今季もエンジニアは絶賛募集中です。特に以下の内容に興味ある方お待ちしてます。

  • 検索システム

  • 高速なスクレイピングとデータ処理システム

WASM/Rustでゴリゴリコードをかけるポジションあるのでぜひお声がけください。こちらのフォームから「ミズノとカジュアル面談希望します!」でご連絡ください。

明日は期待の若手@ryu19-1さんが担当です。よろしく!

[Google Apps Script] スクリプトの並列実行によって実行時間制限をクリアする方法


この記事が気に入ったらサポートをしてみませんか?