WebAssemblyをRustで試す
Webでより高速なWebアプリケーションを実行するための仕組みとして注目されているのがWebAssemblyです。バイナリファイルであり、あらかじめコンパイルされていることでソースコードを簡単に見られてしまうJavaScriptの欠点を補うことができます。
現在、CやC++で書くことが多いWebAssemblyですが、Rustも着実に対応が進んでいます。ついに Rust単体でWebAssemblyをコンパイルする(Emscripten無し) にあるようにRustだけでWebAssembly向けにコンパイルができるようになりました。
今回はそちらのレビューになります。
RustはC/C++に比べると分かりやすい言語だと思います。型推測もあり、スクリプト言語のように書けます。今回はJavaScriptとの速度比較用に、以下のようなコードにしてみました。時間をかけるため、あえてループを繰り返しています。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[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 | |
} |
これをコンパイルします。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
rustc +nightly –target wasm32-unknown-unknown -O main.rs –crate-type=cdylib |
その結果 main.wasm
というファイルが生成されます。
呼び出し方
WebAssemblyは script タグで呼び出せる訳ではありません。Ajaxで取得する必要があります。以下の処理で sum という関数が使えるようになります。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 と判断されます。実行は普通の関数と変わりません。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> sum(10) | |
<- 495 |
JavaScriptとの速度比較
JavaScriptでは以下のようなコードで試しました。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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アプリケーションが開発できるようになるでしょう。
コメントは受け付けていません。