Slide 1

Slide 1 text

Multithreading WebAssembly by Rust fukuoka.rs vol.6 pixiv Inc. petamoriken 2019.11.8

Slide 2

Slide 2 text

2 自己紹介まわり ● 主にフロントエンドエンジニア ● ECMAScript や WHATWG DOM を追うのが好き ● WebAssembly をほどほど追ってる ● 最近引っ越してネット回線がない状態が続いていて 辛い 11/20(水) 19:30~ Three.js Meetup Tokyo #0 サテライト会場を福岡でやるのでよければどうぞ https://connpass.com/event/154480/ petamoriken 課題解決部

Slide 3

Slide 3 text

3 WebAssembly とは ● アセンブリでないバイトコード ● 豊富な実行環境がある ○ モダンブラウザ Chrome / Firefox / Safari / Edge ○ Node.js v8 以降(AWS Lambda, BigQuery など) ○ Wasmer というランタイムを使えば Rust / C / Go / Ruby などで実行できる ● ECMAScript と似た策定プロセスを取っている

Slide 4

Slide 4 text

4 WebAssembly W3C の策定プロセス ● Phase 1 Feature Proposal ○ 機能追加が承認される ● Phase 2 Proposed Spec Text Available ○ 最初の Spec テキストが作られる ● Phase 3 Implementation Phase ○ Spec テキストが完成し、レビューが完了する ● Phase 4 Standardize the Feature ○ 1つのツールチェイン、2つ以上の実行環境が作られ、承認される

Slide 5

Slide 5 text

5 Phase 2 Threads まだ仕様が確定していないが Desktop Chrome に先行実装されている https://developers.google.com/web/updates/2018/10/wasm-threads

Slide 6

Slide 6 text

ブラウザにおけるスレッドは SharedArrayBuffer と Web Workers API を用いる ● SharedArrayBuffer (Atomics API) ○ スレッド間で共有できる特別な ArrayBuffer(バイト列) ○ Atomics API を使って割り込みが起きないようにする ○ Spectre 脆弱性の影響で現在 Desktop Chrome のみ扱える ● Web Workers API ○ スレッドを作る DOM API ○ もちろん SharedArrayBuffer を共有することができる 6 Phase 2 Threads

Slide 7

Slide 7 text

● 先程の Chrome の記事では C で pthread を使ったコード例が載っている ○ Emscripten を使ってビルドする ○ ビルドすると Wasm とグルーコードの JavaScript が出力される ● Rust で似たコードを書いてビルドすればスレッドが扱えるのでは!? 7 Phase 2 Threads emcc -O2 -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=2 -o test.js test.c

Slide 8

Slide 8 text

8 int main(int argc, char *argv[]) { int fg_val = 54; int bg_val = 42; pthread_t bg_thread; // Create the background thread if (pthread_create(&bg_thread, NULL, bg_func, &bg_val)) { perror("Thread create failed"); return 1; } // Calculate on the foreground thread fg_val = fibonacci(fg_val); // Wait for background thread to finish if (pthread_join(bg_thread, NULL)) { perror("Thread join failed"); return 2; } // Show the result from background and foreground threads printf("Fib(42) is %d, Fib(54) is %d\n", bg_val, fg_val); return 0; }

Slide 9

Slide 9 text

9 extern "C" { fn console_log(num: f64); } #[no_mangle] pub extern "C" fn main() { let normal = 54; let background = 42; let handler = std::thread::spawn(move || fibonacci(background)); let normal = fibonacci(normal); let background = handler.join().expect("Unsupported Thread"); unsafe { console_log(normal as f64); console_log(background as f64); } }

Slide 10

Slide 10 text

10

Slide 11

Slide 11 text

● std::thread::spawn を使ったコードは unreachable に変換されてしまう ● 調べてみると Phase 2 Threads は Atomics のみの提案だった ○ ブラウザの SharedArrayBuffer は扱えるが Web Workers API は扱えない ● Emscripten の場合 JavaScript のグルーコード内でスレッドを作っている https://git.io/JeVk0 11 Multithreading WebAssembly by Rust // Allow HTML module to configure the location where the 'worker.js' file will be loaded from, // via Module.locateFile() function. If not specified, then the default URL 'worker.js' relative // to the main html file is loaded. pthreadMainJs = locateFile(pthreadMainJs); var newWorkers = []; for (var i = 0; i < numWorkers; ++i) { newWorkers.push(new Worker(pthreadMainJs)); } return newWorkers;

Slide 12

Slide 12 text

12 こうだと思っていたが JavaScript WebAssembly WebAssembly Main Thread Background Threads WebAssembly

Slide 13

Slide 13 text

13 こうだった JavaScript WebAssembly JavaScript WebAssembly JavaScript WebAssembly Main Thread Background Threads

Slide 14

Slide 14 text

● Rust でスレッドを扱おうと思ったら ○ 複数の Wasm に分割し、それぞれに対して JavaScript のグルーコードを書く ○ wasm-bindgen で JavaScript のグルーコードを自動生成 ■ 公式の demo があるがうまく実行できてなさそう? ● 将来的には Phase 1 Interface Types によってグルーコードが不要に ○ wasm-bindgen で直接 DOM API を触るようになって JavaScript のグルーコードを 生成しなくなる? ○ wasm32-web, wasm32-node のようにビルドターゲットが増える? 14 Multithreading WebAssembly by Rust

Slide 15

Slide 15 text

● WebAssembly でのマルチスレッドはまだ厳しい ○ そもそもまだ仕様策定中 ○ Wasm の実行環境でスレッドを作り、その中で Wasm を実行する必要がある ○ ブラウザに限って言うとまだ Desktop Chrome でしか扱えない ● Phase 1 Interface Types が来たら世界が変わる(はず) ○ フロントエンド開発でグルーコードも含めて JavaScript が不要になる 15 まとめ