Wasm
◯TODO
- wasm何ができるのかの概要
- 2022年現在どういった状況にあるのか
- 環境構築
- Hello, World
WebAssemblyが生まれた背景は、単純にjsよりももっと早くコードを実行する方法がほしかった為
wasm自体は、webでもアセンブリでもない
wasmの仕様そのものには、特にwebに関するものが入っていない
jsと対比してネイティブな形式に近いだけ
jsの上位互換ではなく、協調して動作させるweb周辺技術の一つ
wasm自体は計算しか出来ない
計算をjsよりも速く実行できる様に設計されている
wasmはプラグインとして使いやすい設計
利用する側からimportするような記述がない限り、wasm自体がTCPコネクションを開いたりといったことがない
wasmはコンパイル先の対象となるバイトコード
バイトコードなので、そもそもコンパイラが必要
GoでもC++でもRustでもよい
wasmで書かれたコードが高速に実行できる必要があるのはもちろんだが、それを利用するために、
wasmのコードのダウンロード、パース、コンパイルに時間がかかっていては意味がない。
パースやコンパイルがしやすいフォーマットでないといけない。
Wasmで書かれたプログラムはどんなCPUでもどんなOSでもwasmのvmがある限りは同じ様に動くことを意図して設計されている。
wasmをブラウザで扱う場合、ブラウザはスクリプトをjsしか解釈しないので、
結局jsで出来ること以上のことはできない
似たような取り組みにNaCl,PNaClやasm.jsなどが昔からある
現時点で、メジャーなブラウザはwasmをサポートしている
そのへんのwebサイトを開くだけでもwasmが裏で動いている
3D、動画もwasmに頼れば速く動かせる、google meetのぼかし機能やバーチャル背景もwasm
サーバサイドにwasmを利用するケースも考えられる
wasmでの画像加工など
wasmは、画期的な夢のような技術だと思われるかもしれないが、
Javaが大昔から目指していたものであるし、ブラウザではasm.jsなどもそうだ
既存技術と比べて飛び抜けたものではない。
ただ、高速に動作し、CPUのアーキテクチャやOSでもに非依存、特定のVMでない環境で動作できる、ベンダー比依存などの部分はwasmの大きな強み
JSやTSの代替技術ではない。あくまで共存する技術
なので、信じられないほど爆発的に普及するものでもない
FlutterやBlazorはwasmを利用することができる為、
結果的にこれらのおかげでwasmが普及する可能性はある。
普及することで、これまでは存在しなかった要件がwebに求められることになる
計算がエグい今より何倍もリッチなエフェクトや機械学習など
js/tsとwasmの両方を書き分けられるのがベストだが、
システム案件においては、まだそういったことは必要なさそう
WASM対応フロントエンドフレームワーク
Yew(Rust)
Blazor(MS開発、VueとReactのあいだっぽい感覚)
TeaVM(Java)
Vogu(Go、html+Go的な感覚)
現状は言うまでもなく今後のWasmの発展をもってしても、JavaScriptを過去のものにするようなことはないでしょう
「Reference Types」とは、JavaScriptの参照オブジェクトをそのままWasmの関数に渡したり、Wasmの関数から返したりできるようにする、という仕様
環境
Rustインストール
curl https://sh.rustup.rs -sSf | sh
source入力でターミナル入力でrustupを利用可能にする
source $HOME/.cargo/env
cargoコマンドが利用できるか確認
cargo --version
rustのツールチェインを更新
rustup update
rustのhello worldだけしてみる。
- main.rsというファイルを作る
- fn main() { println!("hello rust"); } という記述を行う
- rustc main.rsで、ビルドファイルを作成(mainという名前のファイルが生成される)
- ./mainで実行
WebAssemblyへのコンパイル機能を有効化
rustup target add wasm32-unknown-unknown
cargoについて
- Rustのビルドシステム兼パッケージマネージャ
https://doc.rust-jp.rs/book-ja/ch01-03-hello-cargo.html
Rust書いている人をRustaceanというみたい
cargo new ◯◯ でプロジェクト作成可能
create-react-app的な感覚
cargo newで作成したディレクトリ内は、以下が作成される
Cargo.toml src/main.rs
Cargo.tomlに下記を追記
[lib]
crate-type = ["cdylib"]
lib.rsを下記にする
#[no_mangle]
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
2つの符号付き32bit整数を和として返す
#[no_mangle] を記載することで、addという関数名のままjs側で実行できるようになる
↓webAssemblyにコンパイル
cargo build --target=wasm32-unknown-unknown --release
index.htmlを作成し、以下を記
const wasm = './target/wasm32-unknown-unknown/release/wasm_dev_book_hello_wasm.wasm'
fetch(wasm)
.then((response) => response.arrayBuffer())
.then((bytes) => WebAssembly.instantiate(bytes, {}))
.then((results) => {
const { add } = results.instance.exports
console.log(add(1, 2))
})
wasmファイルをfetch
↓
arrayBufferでバイナリ配列化する
↓
バイナリ配列をWebAssemblyのコードとして、インスタンス化
↓
WebAssemblyインスタンスからadd関数にアクセスして利用
Webサーバで確認
npx http-server .
Firefox 58 の新機能として、 WebAssembly モジュールを基礎となるソースから直接コンパイルおよびインスタンス化する機能があります。
これは WebAssembly.compileStreaming() と WebAssembly.instantiateStreaming() メソッドを使用して実現します。
これらのメソッドは、バイトコードを直接 Module/Instance インスタンスに変換することができるので、Response を ArrayBuffer に別途格納する必要がないため、ストリーミングではない対応するメソッドよりも簡単になっています。
fetchと WebAssembly.instantiateを利用するのは古い
WebAssembly.instantiateStreaming()が新しく、効率的
importObject
var importObject = { imports: { imported_func: arg => console.log(arg) } };
WebAssembly.instantiateStreaming(fetch('simple.wasm'), importObject)
.then(obj => obj.instance.exports.exported_func());
WebAssembly.instantiateStreamingを利用すると、
下記のようにfetch→arrayBuffer→WebAssembly.instantiateをまとめて記述可能
fetch(wasm)
.then((response) => response.arrayBuffer())
.then((bytes) => WebAssembly.instantiate(bytes, imports))
↓
WebAssembly.instantiateStreaming(fetch(wasm), imports).then((results) => {
画像加工をフロントエンド側だけでやるとかか
↓audacityをweb上で動かせるようにしたやつ。確かにこれはwasmじゃないとできなさそう