WebAssembly スレッドのサポートは、オリジン トライアルとして Chrome 70 でリリースされました。
WebAssembly(Wasm)を使用すると、C++ やその他の言語で記述されたコードをコンパイルして、ウェブ上で実行できます。ネイティブ アプリの非常に便利な機能の 1 つは、並列計算のプリミティブであるスレッドを使用できることです。ほとんどの C および C++ デベロッパーは、アプリケーション内のスレッド管理用の標準化された API である pthreads に精通しています。
WebAssembly コミュニティ グループは、スレッドをウェブに導入して、実際のマルチスレッド アプリケーションを実現するための取り組みを進めています。この取り組みの一環として、V8 は WebAssembly エンジンのスレッドに必要なサポートを実装し、オリジン トライアルを通じて利用できます。オリジン トライアルを使用すると、デベロッパーは新しいウェブ機能を完全に標準化する前に試すことができます。これにより、勇敢なデベロッパーから実際のフィードバックを収集できます。これは、新機能の検証と改善に不可欠です。
Chrome 70 リリースでは、WebAssembly のスレッドがサポートされています。関心をお持ちのデベロッパーは、ぜひこの機能を使用してフィードバックをお寄せください。
スレッド?Worker はどうですか?
ブラウザは 2012 年の Chrome 4 以降、Web Worker による並列処理をサポートしています。実際、「メインスレッド上」などの用語はよく聞きます。ただし、Web Worker は変更可能なデータを相互に共有せず、通信にメッセージ パッシングに依存します。実際、Chrome はそれぞれに新しい V8 エンジン(アイソレーション)を割り当てます。アイソレートはコンパイルされたコードも JavaScript オブジェクトも共有しないため、pthreads などの可変データを共有できません。
一方、WebAssembly スレッドは、同じ Wasm メモリを共有できるスレッドです。共有メモリの基盤となるストレージは、SharedArrayBuffer によって実現されます。これは、ワーカー間で単一の ArrayBuffer の内容を同時に共有できる JavaScript プリミティブです。各 WebAssembly スレッドは Web Worker で実行されますが、共有 Wasm メモリにより、ネイティブ プラットフォームと同様に動作できます。つまり、Wasm スレッドを使用するアプリケーションは、従来のスレッド アプリケーションと同様に、共有メモリへのアクセスを管理する必要があります。pthreads を使用する C または C++ で記述された既存のコード ライブラリは数多くあり、Wasm にコンパイルしてトゥルースレッド モードで実行できるため、より多くのコアが同じデータを同時に処理できます。
簡単な例
スレッドを使用する簡単な「C」プログラムの例を次に示します。
#include <pthread.h>
#include <stdio.h>
// Calculate Fibonacci numbers shared function
int fibonacci(int iterations) {
int val = 1;
int last = 0;
if (iterations == 0) {
return 0;
}
for (int i = 1; i < iterations; i++) {
int seq;
seq = val + last;
last = val;
val = seq;
}
return val;
}
// Start function for the background thread
void *bg_func(void *arg) {
int *iter = (void *)arg;
*iter = fibonacci(*iter);
return arg;
}
// Foreground thread and main entry point
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(6 * 9) is %d\n", bg_val, fg_val);
return 0;
}
このコードは、2 つの変数 fg_val
と bg_val
を宣言する main()
関数で始まります。fibonacci()
という関数もあり、この例では両方のスレッドによって呼び出されます。main()
関数は、pthread_create()
を使用してバックグラウンド スレッドを作成します。このスレッドのタスクは、bg_val
変数の値に対応するフィボナッチ数シーケンス値を計算することです。一方、フォアグラウンド スレッドで実行されている main()
関数は、fg_val
変数に対してこれを計算します。バックグラウンド スレッドの実行が完了すると、結果が出力されます。
スレッド サポート用にコンパイルする
まず、emscripten SDK をインストールする必要があります。バージョン 1.38.11 以降が推奨されます。ブラウザで実行するスレッドを有効にしてサンプルコードをビルドするには、追加のフラグ 2 つを emscripten emcc コンパイラに渡す必要があります。コマンドラインは次のようになります。
emcc -O2 -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=2 -o test.js test.c
コマンドライン引数 -s USE_PTHREADS=1
は、コンパイルされた WebAssembly モジュールのスレッド サポートを有効にします。引数 -s PTHREAD_POOL_SIZE=2
は、2 つのスレッドのプールを生成するようコンパイラに指示します。
プログラムの実行時に、WebAssembly モジュールが読み込まれ、スレッドプール内の各スレッドに Web Worker が作成され、各ワーカー(この場合は 2 つ)とモジュールが共有されます。これらのワーカーは、pthread_create()
が呼び出されるたびに使用されます。各ワーカーは同じメモリを使用して Wasm モジュールをインスタンス化し、連携できるようにします。V8 7.0 の最新の変更では、ワーカー間で渡される Wasm モジュールのコンパイル済みネイティブ コードを共有します。これにより、非常に大規模なアプリケーションでも多くのワーカーにスケーリングできます。スレッドプール サイズがアプリケーションに必要なスレッドの最大数と等しくなるようにすることをおすすめします。そうしないと、スレッドの作成が失敗する可能性があります。一方、スレッドプールのサイズが大きすぎると、不要な Web Worker が作成され、メモリを使用するだけで何もしません。
試してみる方法
WebAssembly モジュールをすばやくテストするには、Chrome 70 以降で試験運用版の WebAssembly スレッド サポートを有効にします。ブラウザで URL about://flags
に移動します。
次に、次のような試験運用版の WebAssembly スレッド設定を探します。
次のように設定を [有効] に変更し、ブラウザを再起動します。
ブラウザを再起動したら、次のコンテンツのみを含む最小限の HTML ページで、スレッド化された WebAssembly モジュールの読み込みを試みます。
<!DOCTYPE html>
<html>
<title>Threads test</title>
<body>
<script src="test.js"></script>
</body>
</html>
このページを試すには、なんらかの形式のウェブサーバーを実行して、それをブラウザから読み込む必要があります。これにより、WebAssembly モジュールが読み込まれて実行されます。DevTools を開くと、実行の出力が表示されます。コンソールに、次の出力画像のような出力が表示されます。
スレッドを使用した WebAssembly プログラムが正常に実行されました。上記の手順に沿って、独自のスレッド化されたアプリケーションを試してみることをおすすめします。
オリジン トライアルによるフィールド テスト
ブラウザで試験運用版フラグをオンにしてスレッドを試すことは開発目的では問題ありませんが、フィールドでアプリケーションをテストする場合は、オリジン トライアルでテストできます。
オリジン トライアルでは、ドメインに関連付けられたテストトークンを取得して、ユーザーと一緒に試験運用版機能を試すことができます。その後、アプリをデプロイして、テストしている機能をサポートしているブラウザ(この場合は Chrome 70 以降)で動作することを想定できます。オリジン トライアルを実施するための独自のトークンを取得するには、こちらの申請フォームをご利用ください。
上記のシンプルな例はオリジン トライアル トークンを使用してホストされているため、何も構築しなくても実際に試すことができます。
4 つのスレッドを並行して実行して ASCII アートを作成する方法については、こちらのデモもご覧ください。
ご意見をお寄せください
WebAssembly スレッドは、アプリケーションをウェブに移植する場合に非常に便利な新しいプリミティブです。WebAssembly 環境で pthreads のサポートを必要とする C および C++ のアプリケーションとライブラリを実行できるようになりました。
Google では、この機能をお試しになったデベロッパーの皆様からのフィードバックをお待ちしています。このフィードバックは、標準化プロセスに役立つ情報を提供し、その有用性を検証するのに役立ちます。フィードバックを送信する最善の方法は、問題を報告するか、WebAssembly コミュニティ グループの標準化プロセスに参加することです。