WebAssemblyをRustで試す
Webでより高速なWebアプリケーションを実行するための仕組みとして注目されているのがWebAssemblyです。バイナリファイルであり、あらかじめコンパイルされていることでソースコードを簡単に見られてしまうJavaScriptの欠点を補うことができます。
現在、CやC++で書くことが多いWebAssemblyですが、Rustも着実に対応が進んでいます。ついに Rust単体でWebAssemblyをコンパイルする(Emscripten無し) にあるようにRustだけでWebAssembly向けにコンパイルができるようになりました。
今回はそちらのレビューになります。
RustはC/C++に比べると分かりやすい言語だと思います。型推測もあり、スクリプト言語のように書けます。今回はJavaScriptとの速度比較用に、以下のようなコードにしてみました。時間をかけるため、あえてループを繰り返しています。
#[no_mangle] | |
pub fn sum(a: i32) -> i32 { | |
let mut total = 0; | |
for x in 0..a { | |
total += x; | |
for y in 0..a { | |
total += y; | |
} | |
} | |
total | |
} |
これをコンパイルします。
rustc +nightly –target wasm32-unknown-unknown -O main.rs –crate-type=cdylib |
その結果 main.wasm
というファイルが生成されます。
呼び出し方
WebAssemblyは script タグで呼び出せる訳ではありません。Ajaxで取得する必要があります。以下の処理で sum という関数が使えるようになります。
var sum = null; | |
fetch('main.wasm') | |
.then((response) => response.arrayBuffer()) | |
.then((bytes) => WebAssembly.instantiate(bytes, {})) | |
.then((results) => { | |
const instance = results.instance; | |
sum = instance.exports.sum; | |
}); |
sum 自体は Native Code と判断されます。実行は普通の関数と変わりません。
> sum(10) | |
<- 495 |
JavaScriptとの速度比較
JavaScriptでは以下のようなコードで試しました。
total = 0; | |
for (var x = 0; x < i; x++) { | |
total += x; | |
for (var y = 0; y < i; y++) { | |
total += y; | |
} | |
} | |
console.log(total); |
それぞれ3回繰り返した平均値です(単位は ms)。
回数 | Rust | JavaScript |
---|---|---|
100 | 190 | 513 |
1,000 | 165 | 3979 |
2,000 | 163 | 36593 |
5,000 | 172 | 337251 |
10,000 | 209 | 1427188 |
WebAssemblyの実行結果は回数に殆ど関係しませんでした。10,000回繰り返した時にも275/176/177msといった数字で、もっと回数の少ない時と変わりません。逆にJavaScriptは処理回数によってリニアに処理時間が延びている印象です。
WebAssemblyの欠点
現状のWebAssemblyはDOMやWeb API、GCに対応していません。そのため利用範囲が限られてしまうでしょう。将来的にはこれらのAPIにも対応が予定されています。
Rust自体は学習しやすい言語だと思います。それによって現状のWebを高速化できるので今後に期待した技術です。現状についてはJavaScriptから呼び出される補助的な技術ですが、将来的にはC/C++/Rustをはじめ、多くの言語でWebアプリケーションが開発できるようになるでしょう。
コメントは受け付けていません。