Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Rust + WebAssembly Performance: JavaScript vs. wasm-bindgen vs. Raw WASM (with SIMD)

2025年09月29日に「Dev.to」が公開したITニュース「Rust + WebAssembly Performance: JavaScript vs. wasm-bindgen vs. Raw WASM (with SIMD)」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

計算が重いWebタスクでJavaScriptの代わりにRust+WebAssembly(WASM)を使う性能を比較。結果、配列操作ではRaw WASMがJavaScriptより約4倍、SIMD活用で約6倍高速だった。用途に応じてJS、wasm-bindgen、Raw WASMを使い分けると良い。

ITニュース解説

現代のWebアプリケーション開発では、ユーザーインターフェースや基本的な処理にJavaScriptが標準的に使われている。これはJavaScriptが軽量で、インタープリタ型であり、V8(ChromeやNode.js)やSpiderMonkey(Firefox)といった現代のJavaScriptエンジンによって高度に最適化されているためだ。しかし、大量のデータを扱う計算集約型のタスクでは、JavaScriptの性能が必ずしも要求を満たせない場面も出てくる。

そこで注目されるのが、Rust言語とWebAssembly(WASM)の組み合わせだ。Rustはメモリ安全性に優れ、高速な実行が可能であり、WebAssemblyとの連携も「wasm-bindgen」や「wasm-pack」といったツールを通じてスムーズに行える。WebAssembly自体は、Webブラウザ内で高性能かつポータブル、そして安全にコードを実行するために設計されたバイナリ形式である。

この記事では、Webアプリケーションで性能が求められる計算タスクを解決するために、異なる4つのアプローチでその性能を比較検証している。具体的には、純粋なJavaScriptによる実装、Rustコードを「wasm-bindgen」を通じてWebAssemblyにコンパイルしたもの、Rustから直接WebAssemblyの低レベルな機能を利用する「Raw WASM」での実装、そして「Raw WASM」に加えて「SIMD」命令を適用した実装の四つを比較する。この比較を通じて、それぞれの方法がどのような特性を持ち、どのような場面で有効なのかを理解できる。

検証対象のタスクは二つだ。一つは「配列の変更」で、Float32Arrayという特定の型の数値配列の全要素に2.0を加算する処理だ。このタスクは、メモリの管理方法や反復処理の速度が性能に大きく影響するため、各アプローチの効率性を測る上で重要となる。もう一つは「フィボナッチ数列の計算」で、再帰を使わず反復処理でフィボナッチ数を求める。これは純粋な計算性能を比較するのに適したタスクだ。

ここで、比較に使われる主要な技術要素について簡単に説明する。「wasm-bindgen」は、RustとJavaScriptの間でデータをやり取りするための橋渡しをするライブラリとツールのセットである。これにより、Rustで書かれた関数をJavaScriptから呼び出したり、その逆を行ったりできる。次に「wasm-pack」は、RustプロジェクトをWebAssembly向けにビルドするための一連のプロセスを自動化するコマンドラインインターフェース(CLI)だ。RustコードをWebAssemblyにコンパイルし、「wasm-bindgen」を使ってJavaScriptとの連携部分を生成し、最終的にnpmパッケージとして配布可能な形にまとめる役割を果たす。これは、Rust+WebAssemblyプロジェクトの開発ワークフローを大幅に簡素化するツールと言える。また、「Float32Array」はJavaScriptが提供する特殊な配列で、32ビット浮動小数点数のみを格納する。通常のJavaScript配列とは異なり、メモリ上にデータを連続して配置するため、数値計算において高い効率性とメモリ利用効率を実現する。WebGLや音声処理、数値解析などの分野で特に有用だ。

それでは、各アプローチの実装と特性を見ていこう。

「純粋なJavaScript」による実装は、Web開発において最も一般的な方法だ。forループを使って配列の要素を一つずつ変更したり、反復処理でフィボナッチ数列を計算したりする。これは非常にシンプルで理解しやすいが、計算負荷の高いタスクでは性能がボトルネックになる可能性がある。

次に、「wasm-bindgen」を使ったRustとWebAssemblyの連携だ。JavaScriptで作成した効率的な「Float32Array」をRust関数に渡せる。しかし、この際にJavaScriptのメモリからRustのメモリへデータをコピーするオーバーヘッドが発生する。配列が小さい場合はこのオーバーヘッドは無視できるが、大規模な配列や非常に性能が要求される状況では、このコピー処理が性能に影響を与える可能性がある。Rust側では、wasm_bindgenアトリビュートを使ってJavaScriptから呼び出せる関数を定義し、配列をRustのスライス(&[f32])として受け取って処理する。フィボナッチ計算も同様に、Rustで実装した関数をJavaScriptから呼び出す形となる。

三つ目のアプローチは「Raw WASM」だ。これは「wasm-bindgen」のような高レベルな抽象化層を避け、Rustから直接WebAssemblyの低レベルなメモリ操作を利用する方法を指す。具体的には、Rustのコードでポインタ(*mut f32)を使い、JavaScript側で確保したメモリ領域に直接アクセスしてデータを操作する。これにより、JavaScriptとRust間のデータコピーのオーバーヘッドを避けることができる。ただし、このような直接的なメモリ操作はRustの通常のメモリ安全性の保証から外れるため、「unsafe」ブロックを使って慎重にコードを書く必要がある。これは、システムエンジニアがより低レベルな制御を必要とする場合に選択するアプローチだ。

そして四つ目は、「Raw WASM」にさらに「SIMD」命令を組み込んだ実装だ。「SIMD」(Single Instruction, Multiple Data)は、一つの命令で複数のデータを同時に処理する、プロセッサの特殊な命令セットのことだ。配列の要素ごとに同じ操作を繰り返すような並列化が可能なタスクでは、SIMD命令を利用することで処理速度を大幅に向上させることができる。このSIMDをWebAssemblyで利用するには、Rustのコンパイル時に特定のフラグ(RUSTFLAGS="-C target-feature=+simd128")を設定する必要がある。また、すべてのWebブラウザがSIMD命令をサポートしているわけではない点も考慮が必要だが、最近の主要なブラウザでは広くサポートが進んでいる。このSIMD実装も、Raw WASMと同様にポインタを直接操作し、「unsafe」ブロックを使用する。

これらのアプローチをベンチマークで比較した結果が示されている。配列変更タスクでは、性能に大きな差が現れた。純粋なJavaScriptが平均1.403ミリ秒かかったのに対し、「wasm-bindgen」を使った方法はわずかに遅い1.623ミリ秒だった。これは前述のデータコピーのオーバーヘッドが影響していると考えられる。しかし、「Raw WASM」では平均0.353ミリ秒と、JavaScriptの約4倍の速さを達成した。さらに「Raw WASM (SIMD)」では平均0.231ミリ秒と、JavaScriptの約6倍もの高速化を実現している。この結果は、計算負荷の高い配列操作において、低レベルなWebAssemblyとSIMD命令の組み合わせが非常に強力であることを明確に示している。

一方、フィボナッチ数列の計算タスクでは、どの方法も非常に短い時間で完了し、性能差はほとんど意味をなさないほど小さかった。例えば、純粋なJavaScriptが0.00120ミリ秒だったのに対し、「Raw WASM」は0.00019ミリ秒だった。これらの数値は非常に小さく、計算自体が軽量であるため、実装方法の違いが目立った性能差として現れなかったと言える。

このベンチマーク結果から、いくつかの結論が導き出される。まず、Webアプリケーションの単純な処理や、性能がそこまで厳しく求められない場合には、開発のしやすさから純粋なJavaScriptを使うのが最も合理的だ。次に、既にJavaScriptで多くの部分が書かれているプロジェクトに、Rustで実装した一部のロジックを統合したい場合には、「wasm-bindgen」が非常に便利である。多少の性能オーバーヘッドはあっても、開発の効率性を優先する場面で有効な選択肢となる。

そして、大規模なデータ処理や高い計算性能が求められるタスク、特にメモリ操作が頻繁に行われるような場面では、「Raw WASM」の利用が検討される。これはJavaScriptや「wasm-bindgen」よりもはるかに高速な実行が可能だが、Rustのメモリ安全性の保証を一時的に解除する「unsafe」コードを書く必要があり、より慎重なメモリ管理と低レベルなプログラミングの知識が求められる。さらに、配列処理のように並列化しやすい計算タスクであれば、「SIMD」命令を利用した「Raw WASM」が最高の性能を発揮する。しかし、これも特別なコンパイル設定が必要であり、ブラウザのサポート状況も確認する必要がある。

これらの結論は小規模なベンチマークに基づいているため、あくまで参考として捉えるべきだ。しかし、システムエンジニアを目指す上で、Webアプリケーションの性能を最大化するための異なるアプローチとそのトレードオフを理解することは非常に重要だ。適切な技術選択は、アプリケーションの成功に直結するからだ。

関連コンテンツ

関連IT用語