Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ウェブエンジニアでもWasmを使いたい!

asuka
August 24, 2024

 ウェブエンジニアでもWasmを使いたい!

フロントエンドカンファレンス北海道 2024

asuka

August 24, 2024
Tweet

More Decks by asuka

Other Decks in Technology

Transcript

  1. ウェブにおけるWasmの状況 とりあえずなんでもブラウザで動かしてみる - PHPをブラウザで動かしてみた - Javaをブラウザで動かしてみた - Linuxをブラウザで動かしてみた JavaScript以外でのウェブアプリケーション開発 -

    Rust製のウェブアプリケーションフレームワーク - DartやGoのWasm対応など → まだJavaScriptで良いかもという空気 9 色々動いてすごい JS以外の選択肢が出てきた - 新しい言語覚えるの大変 😣 - JavaScript使っていてパフォーマンスに 困る場面がそれほど多くない
  2. ウェブエンジニアでもWasmを使いたい!! 1. WebAssemblyとは ◦ JavaScriptとWasmの違い 2. Wasmが速い理由 ◦ Wasmが期待するほどではなかったと言われる理由 ◦

    本当に期待するほどではなかったのか? 3. AssemblyScript 4. Wasmの使い所 話さないこと - Wasmの最前線 - サーバーやOSでのWasmの活用 - 今後のWasmに期待していること → 懇親会などで話しましょう !!! 13 このセッションを聞けば, プロジェクトにWasmを導入できるようになる
  3. JavaScriptとWasmの違い:フォーマット 18 export function add(a, b) { return a +

    b; } 0061736d0100000001070160027f7f017f030201 000707010361646400000a09010700200020016a 0b0018046e616d65010601000361646402090100 02000161010162 テキストフォーマット バイナリフォーマット JavaScript Wasm
  4. JavaScriptとWasmの違い:フォーマット 19 export function add(a, b) { return a +

    b; } 0061736d0100000001070160027f7f017f030201 000707010361646400000a09010700200020016a 0b0018046e616d65010601000361646402090100 02000161010162 テキストフォーマット ⭕ 人が読める バイナリフォーマット ❌ 人が読めない JavaScript Wasm
  5. JavaScriptとWasmの違い:フォーマット 20 export function add(a, b) { return a +

    b; } 0061736d0100000001070160027f7f017f030201 000707010361646400000a09010700200020016a 0b0018046e616d65010601000361646402090100 02000161010162 バイナリフォーマット ❌ 人が読めない fn add(a: i32, b: i32) -> i32 { a + b } Rustなどの言語からWasmをビルドする テキストフォーマット ⭕ 人が読める
  6. 21 export function add(a, b) { return a + b;

    } (module (func $add (param $a i32) (param $b i32) (result i32) local.get $a local.get $b i32.add ) (export "add" (func $add)) ) 0061736d0100000001070160027f7f017f030201 000707010361646400000a09010700200020016a 0b0018046e616d65010601000361646402090100 02000161010162 人が読めるようにすると ... JavaScriptとWasmの違い:フォーマット WebAssembly Text Format
  7. 22 export function add(a, b) { return a + b;

    } (module (func $add (param $a i32) (param $b i32) (result i32) local.get $a local.get $b i32.add ) (export "add" (func $add)) ) なんとなく同じプログラムと いうことがわかる 0061736d0100000001070160027f7f017f030201 000707010361646400000a09010700200020016a 0b0018046e616d65010601000361646402090100 02000161010162 人が読めるようにすると ... JavaScriptとWasmの違い:フォーマット WebAssembly Text Format
  8. 23 export function add(a, b) { return a + b;

    } (module (func $add (param $a i32) (param $b i32) (result i32) local.get $a local.get $b i32.add ) (export "add" (func $add)) ) なんとなく同じプログラムと いうことがわかる 0061736d0100000001070160027f7f017f030201 000707010361646400000a09010700200020016a 0b0018046e616d65010601000361646402090100 02000161010162 人が読めるようにすると ... 1 local.get $a 1 local.get $b 2 3 i32.add Wasmはスタックマシン JavaScriptとWasmの違い:フォーマット WebAssembly Text Format
  9. 25 JavaScriptを実行する方法 export function add(a, b) { return a +

    b; } <!DOCTYPE html> <html> <body> <script type="module"> import { add } from "./main.js"; console.debug(add(1, 2)); // 3 </script> </body> </html> HTML上にインポートするだけ JavaScriptとWasmの違い:実行方法
  10. JavaScriptとWasmの違い:実行方法 26 Wasmを実行する方法 0061736d0100000001070160027f7f017f030201 000707010361646400000a09010700200020016a 0b0018046e616d65010601000361646402090100 02000161010162 <!DOCTYPE html> <html>

    <body> <script type="module"> const binary = await fetch(new URL("main.wasm", import.meta.url)); const module = await WebAssembly.compile(await binary.arrayBuffer()); const instance = await WebAssembly.instantiate(module); console.debug(instance.exports.add(1, 2)); // 3 </script> </body> </html> 1. Wasmファイルをfetchする 2. WasmファイルをWasmモジュールに変換する 3. Wasmモジュールをインスタンス化する → Wasmの躓きポイントの一つ 現状はJavaScriptを介して 実行する必要がある (少し面倒)
  11. 28 Wasmが速い理由 export function add(a, b) { return a +

    b; } 0061736d0100000001070160027f7f017f030201 000707010361646400000a09010700200020016a 0b0018046e616d65010601000361646402090100 02000161010162 テキストフォーマット ⭕人が扱いやすい バイナリフォーマット ❌人が扱いにくい
  12. 29 Wasmが速い理由 export function add(a, b) { return a +

    b; } 0061736d0100000001070160027f7f017f030201 000707010361646400000a09010700200020016a 0b0018046e616d65010601000361646402090100 02000161010162 テキストフォーマット ❌計算機が扱いにくい バイナリフォーマット ⭕計算機が扱いやすい
  13. Wasmのバイナリは計算機が解釈しやすいよう設計されている 32 Wasmが速い理由 0061736d0100000001070160027f7f017f030201 000707010361646400000a09010700200020016a 0b0018046e616d65010601000361646402090100 02000161010162 (type 0 (func

    (param i32 i32) (result i32)) (export "add" (func 0)) (func 0 (type 0) local.get 0 local.get 1 i32.add ) 20 00 20 01 6a 20 → local.get 6a → i32.add 一意に解釈できる こう解釈できる
  14. JavaScript → インタプリタ(テキストの意味を解釈して実行する) Wasm → コンパイル結果を実行する 36 インタプリタだから遅いよね〜 コンパイル言語だから速いよね〜 Wasmが期待するほどではなかったと言われる理由

    JavaScript Wasm コンパイル言語だから速い インタプリタだから遅い JITコンパイルされて速い 多くのウェブアプリが JITコンパイルで十分だった Wasmって期待するほどでもなかった
  15. JavaScript → インタプリタ(テキストの意味を解釈して実行する) Wasm → コンパイル結果を実行する 38 インタプリタだから遅いよね〜 コンパイル言語だから速いよね〜 本当に期待するほどではなかったのか?

    JavaScript Wasm コンパイル言語だから速い インタプリタだから遅い JITコンパイルされて速い 多くのウェブアプリが JITコンパイルで十分だった Wasmって期待するほどでもなかった
  16. JavaScript → インタプリタ(テキストの意味を解釈して実行する) Wasm → コンパイル結果を実行する 39 インタプリタだから遅いよね〜 コンパイル言語だから速いよね〜 本当に期待するほどではなかったのか?

    JavaScript Wasm コンパイル言語だから速い インタプリタだから遅い JITコンパイルされて速い 多くのウェブアプリが JITコンパイルで十分だった Wasmって期待するほどでもなかった ちょっと待った !!!
  17. JavaScriptよりWasmの方が命令の実行速度が少し速い 本当に期待するほどではなかったのか? 44 // フィボナッチ数 export function fib(n: number): number

    { if (n <= 1.0) { return n; } return fib(n - 1.0) + fib(n - 2.0); } fib(15) → 1,973回 fib(30) → 約270万回 fib(35) → 約3千万回 fib(40) → 約3億3千万回 ※ベンチマーク用に再帰関数を採用しています ※ランタイムによって差異はあります
  18. PCとモバイルの速度比較 本当に期待するほどではなかったのか? 49 fib(40) JavaScript → 741ms Wasm → 378ms

    fib(40) JavaScript → 1532ms Wasm → 467ms x2.1 x1.2 Wasmの方が速度劣化が少ない
  19. Wasmで発生するオーバーヘッドはどうなの? 1. Wasmをロードする時間 2. データを共有する時間 本当に期待するほどではなかったのか? 52 const binary =

    await fetch(new URL("main.wasm", import.meta.url)); const module = await WebAssembly.compile(await binary.arrayBuffer()); const instance = await WebAssembly.instantiate(module); // ... 直接Wasmをインポートすることができない 通信量増えて遅くならない?
  20. Wasmで発生するオーバーヘッドはどうなの? 1. Wasmをロードする時間 2. データを共有する時間 0061736d0100000001070160027f7f017f030201 000707010361646400000a09010700200020016a 0b0018046e616d65010601000361646402090100 02000161010162 本当に期待するほどではなかったのか?

    54 function add(a, b) {↩ return a + b;↩ } 38バイト 9バイト 非常に小さなプログラムの場合,ビルド時の付加情報でJavaScriptよりファイルサイズが大きく見えるが... JavaScriptよりWasmの方がプログラムの記述量は小さくできる がっつり処理を書いた場合, Wasmの方が実行ファイルサイズが 小さくなる可能性はある
  21. Wasmで発生するオーバーヘッドはどうなの? 1. Wasmをロードする時間 2. データを共有する時間 JavaScript 本当に期待するほどではなかったのか? 56 "Hello, world!"

    Wasm "Hello, world!" (func (param $ptr i32) (param $len i32)) コピー exports.foo(ptr, len); 実行 Web API 多くの場合はそれほど問題にならない & あとは実装次第
  22. AssemblyScript AssemblyScriptは,TypeScriptをそのままWasmにコンパイルできる言語. 59 export function add(a: number, b: number): number

    { return a + b; } ./app/lib/calc.ts import { add } from "~/lib/calc"; console.log(add(1, 2)); TypeScriptの場合
  23. AssemblyScript AssemblyScriptは,TypeScriptをそのままWasmにコンパイルできる言語. 60 export function add(a: number, b: number): number

    { return a + b; } ./app/lib/calc.ts import { add } from "~/lib/calc"; console.log(add(1, 2)); import { add } from "~/asbuild/release"; console.log(add(1, 2)); TypeScriptの場合 AssemblyScriptの場合 ↓ $ npm run asbuild ESMと同じノリで扱うことができる
  24. AssemblyScriptは,TypeScriptをそのままWasmにコンパイルできる言語. AssemblyScript 61 export function add(a: number, b: number): number

    { return a + b; } ./app/lib/calc.ts import { add } from "~/lib/calc"; console.log(add(1, 2)); import { add } from "~/asbuild/release"; console.log(add(1, 2)); TypeScriptの場合 AssemblyScriptの場合 ↓ $ npm run asbuild ESMと同じノリで扱うことができる 導入方法 $ npm install -D assemblyscript
  25. AssemblyScriptは,TypeScriptをそのままWasmにコンパイルできる言語. AssemblyScript 62 export function add(a: number, b: number): number

    { return a + b; } ./app/lib/calc.ts import { add } from "~/lib/calc"; console.log(add(1, 2)); import { add } from "~/asbuild/release"; console.log(add(1, 2)); TypeScriptの場合 AssemblyScriptの場合 ↓ $ npx asbuild ESMと同じノリで扱うことができる デモ:http://localhost:3000/add
  26. AssemblyScript AssemblyScriptの良いところ 1. TypeScriptのコードをほぼそのままWasmにコンパイルできる a. オブジェクトの扱いには少し注意が必要 2. コンパイル後のファイルサイズが非常に小さい a. GoやRustなどは処理系の実装が入るので

    Wasmファイルが大きくなりがち 63 export function add(a: number, b: number): number { return a + b; } ./app/lib/calc.ts export * from "../app/lib/calc"; ./assembly/index.ts export import { add } from "~/asbuild/release"; console.log(add(1, 2)); $ npm run asbuild
  27. export function add(a: number, b: number): number { return a

    + b; } AssemblyScriptの良いところ 1. TypeScriptのコードをほぼそのままWasmにコンパイルできる a. オブジェクトの扱いには少し注意が必要 2. コンパイル後のファイルサイズが非常に小さい a. GoやRustなどは処理系の実装が入るので Wasmファイルが大きくなりがち AssemblyScript 64 ./app/lib/calc.ts ./release.js → 653B ./release.wasm → 93B Rustからビルドするよりも コンパクトなWasmファイルになる $ npm run asbuild 書いたままのコードが生成される
  28. export function add(a: number, b: number): number { return a

    + b; } AssemblyScriptの良いところ 1. TypeScriptのコードをほぼそのままWasmにコンパイルできる a. オブジェクトの扱いには少し注意が必要 2. コンパイル後のファイルサイズが非常に小さい a. GoやRustなどは処理系の実装が入るので Wasmファイルが大きくなりがち AssemblyScript 65 ./app/lib/calc.ts ./release.js → 653B ./release.wasm → 93B Rustからビルドするよりも コンパクトなWasmファイルになる $ npx asbuild 書いたままのコードが生成される 既存のNode.js環境に組み込みやすい 👍👍👍
  29. Wasmの使い所 Wasmで扱える数値型: - i32 (u32) - i64 (u64) - f32

    - f64 69 JavaScriptにはnumber (= f64)しかないが, Wasmは整数,小数を扱うことができる
  30. Wasmの使い所 Wasmで扱える数値型: - i8 (u8) - i16 (u16) - i32

    (u32) - i64 (u64) - f32 - f64 70 JavaScriptにはnumber (= f64)しかないが, Wasmは整数,小数を扱うことができる AssemblyScriptはi8 (u8), i16 (u16)型も用意し ている ※ Wasm上の型としてはi32とi64の2つの型しかないが, 「i32.extend8_s」や「i32.extend16_s」といった命令が存在して いるため,i8やi16も扱える
  31. Wasmの使い所 Wasmで扱える数値型: - i8 (u8) - i16 (u16) - i32

    (u32) - i64 (u64) - f32 - f64 71 JavaScriptにはnumber (= f64)しかないが, Wasmには整数,小数を扱うことができる AssemblyScriptはi8 (u8), i16 (u16)型も用意し ている ※ Wasm上の型としてはi32とi64の2つの型しかないが, 「i32.extend8_s」や「i32.extend16_s」といった命令が存在して いるため,i8やi16も扱える デモ:http://localhost:3000/calc
  32. Wasmの使い所 プラグイン機能を提供したい Wasm - 実行時の権限を制限しやすい 73 AssemblyScript - コンパイラがウェブでも動作する Wasmだけだとホスト環境にアクセスできない

    - 閲覧履歴を書き換えられる - HTMLを書き換えられる 󰢃Wasmなら防ぐことができる 安全に実行できる → プラグイン機能に使える
  33. Wasmの使い所 プラグイン機能を提供したい Wasm - 実行時の権限を制限しやすい 74 AssemblyScript - コンパイラがウェブでも動作する Wasmだけだとホスト環境にアクセスできない

    - 閲覧履歴を書き換えられる - HTMLを書き換えられる 󰢃Wasmなら防ぐことができる 安全に実行できる → プラグイン機能に使える ブラウザ上でAssemblyScriptをビルドして 動作確認をすることができる → 書きやすい & 動作確認しやすい
  34. Wasmの使い所 プラグイン機能を提供したい Wasm - 実行時の権限を制限しやすい 75 AssemblyScript - コンパイラがウェブでも動作する Wasmだけだとホスト環境にアクセスできない

    - 閲覧履歴を書き換えられる - HTMLを書き換えられる 󰢃Wasmなら防ぐことができる 安全に実行できる → プラグイン機能に使える ブラウザ上でAssemblyScriptをビルドして 動作確認をすることができる デモ:http://localhost:3000/plugin
  35. Wasmの使い所 プラグイン機能を提供したい Wasm - 安全に実行できる →プラグインを作るのに適している 76 AssemblyScript - コンパイラがウェブでも動作する

    課題:Wasmを何の言語でビルドする ? 他の言語を選ぶことへの心理的ハードル TypeScriptで書くことができる かつシンプルなWasmがビルドされる → AssemblyScriptはWasmの入門に適している
  36. ウェブエンジニアでもWasmを使いたい!! 1. WebAssemblyとは ◦ JavaScriptとWasmの違い 2. Wasmが速い理由 ◦ Wasmが期待するほどではなかったと言われ る理由

    ◦ 本当に期待するほどではなかったのか? 3. AssemblyScript 4. Wasmの使い所 77 プログラミング言語ではなく,コンパイルターゲット 環境に左右されにくい安定した実行速度 数値計算にWasmは強い 安全に実行するための仕組みを提供 計算量を必要とするプログラムほどWasmは輝く Wasmは安定したパフォーマンスを得ることが目的 TypeScriptをWasmにビルドできる 既存のNode.js環境と共存できる