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

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

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for asuka asuka
August 24, 2024

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

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

Avatar for asuka

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環境と共存できる