108
43

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

NRI OpenStandiaAdvent Calendar 2021

Day 8

WebAssemblyが気になるので調べてみた

Last updated at Posted at 2021-12-08

web-assembly-logo

OpenStandiaアドベントカレンダー、今回はWebAssemblyについて取り上げます。

はじめに

最近「WebAssembly」というワードを耳にする機会が増えた気がします。
初めてこの単語を知ったときはアセンブリ言語のようなものをガリガリコーディングすることをイメージしました。
なんで今更アセンブリ、、、と思っていたら上記のイメージとは違っており、うまく活用できれば強力な技術であることがわかったのでこの記事に簡単にまとめます。

想定読者

  • WebAssemblyで何ができるかを知りたい方
  • WebAssemblyの事例や使い所を知りたい方
  • WebAssemblyに興味のある方
  • 基本的なプログラミング用語を理解している方

想定外読者

  • WebAssemblyの技術的な記事を期待している方

1. WebAssembly概要

1.1 WebAssemblyの簡単な説明

WebAssemblyとは「仮想マシン上で動作するバイナリの命令形式」です。
なんのこっちゃという感じですが、仮想マシン上(JavaでいうところのJVMのようなもの)で動作する低級言語であると理解すると良いかと思います。

WebAssemblyは「バイナリの命令形式」と説明しましたが、WebAssemblyにはBinary Format (WASM)Text Format (WAT)の2つのフォーマットがあります。

以下はText Formatの例です。
可読性の低い低級言語ではありますが、読もうと思えば読めるようなフォーマットになっています。

TextFormat
(module
  (func (export "addTwo") (param i32 i32) (result i32)
    local.get 0
    local.get 1
    i32.add))

上記のText FormatのコードをBinary Formatに変換したものがこちらです。
Binary Formatになると見るだけでは理解できません。

BinaryFormat
0061 736d 0100 0000 0107 0160 027f 7f01
7f03 0201 0007 0a01 0661 6464 5477 6f00
000a 0901 0700 2000 2001 6a0b 000e 046e
616d 6502 0701 0002 0000 0100 

ここではText FormatとBinary Formatの例を示しましたが、これらを実際に記述することはほとんどないかと思います。
なぜならWebAssemblyはCやC++、Rust、Goなど様々な言語から上記のWebAssemblyの命令形式へコンパイルして利用できるからです。

WebAssemblyを用いることにより得られるメリットは主に下記の3点だと私は考えています。

  1. JavaScriptではできなかった負荷の大きな処理をブラウザで実行できる
  2. C/C++など既存のソースコードをブラウザで実行できる
  3. フロントとバックの処理を同じ言語で記述できる(→コードの使い回しができる)

実際にこれらのメリットがわかる事例があるので、2 WebAssemblyの活用事例5選で紹介します。

1.2 WebAssemblyの目指すもの

WebAssemblyが目指すゴールは仕様書に記載されています。
これによるとメインとするゴールは「Web環境で高いパフォーマンスを発揮するアプリケーションを実行可能とすること」と記載されています。
一方で、「Web環境を前提としない」とも記載されています。
特定の環境を前提としないため、WebAssemblyは様々な用途に適用できる技術となっています。

WebAssemblyの仕様書にはDesign Goalsとして下記の7項目が挙げられています。

# Goal 概要
1 Fast 最近のハードウェアの性能を活用し、ネイティブコードに近いパフォーマンスを発揮する。
2 Safe コードは検証され、メモリセーフなサンドボックス環境で実行する。これによりデータの破損とセキュリティ違反を防止する。
3 Well-defined 形式的かつ非形式的に容易に説明できる方法で、”有効なプログラム”とその”挙動”を完全かつ正確に定義する。
4 Hardware-independent デスクトップやモバイル端末、組み込み機器を含め、全てのモダンなアーキテクチャの上でコンパイルできる。
5 Language-independent 特定のプログラミング言語やプログラミングモデル、オブジェクトモデルを特別扱いしない。
6 Platform-independent ブラウザやスタンドアロンVMに埋め込める、またはその他の環境へ統合できる。
7 Open プログラムは簡単かつ汎用的な方法で環境と相互運用できる。

また、WebAssemblyの考えるEfficient(効率)Portable(可搬性)は以下の6項目とされています。
WebAssemblyは「Web環境で高いパフォーマンスを発揮するアプリケーションを実行可能とすること」をメインゴールとしていたことを考えるとどれも納得のいく説明がなされています。
とりわけStreamableの項目はブラウザでの利用を想定しているWebAssemblyならではの特徴ではないでしょうか。

# Goal 概要
1 Compact 一般的なテキストやネイティブコードよりもサイズを小さすることで高速に転送可能なバイナリ形式とする。
2 Modular プログラムを小さいパートに分割し、それぞれ独立に転送、キャッシュ、利用できる。
3 Efficient Just-in-Time(JIT)やAhead-of-Time(AOT)コンパイラを用いて、高速な単一パスでデコード・検証・コンパイルができる。
4 Streamable 全てのデータを受信する前に、可能な限り即座にデコード・検証・コンパイルができる。
5 Parallelizable デコード・検証・コンパイルが多数の独立した並列なタスクに分割できる。
6 Portable モダンなハードウェアで一般的にサポートされていないようなアーキテクチャを前提としない。

1.3 WebAssemblyの適用場面

特定の環境や特定の言語をターゲットとしないWebAssemblyは様々な場面で利用できます。
例えば、下記のような用途で利用できます。
やはりメインとなるユースケースは負荷の大きな処理をブラウザで実装したいときではないでしょうか。

  • 動画、画像編集
  • 画像認識
  • 低遅延のVR・AR
  • CAD
  • ゲーム開発
  • 圧縮や暗号化など

2 WebAssemblyの活用事例5選

ここではWebAssemblyを活用した事例を紹介します。

2.1 事例① ブラウザ版GoogleEarth

Google Earth

事例①はブラウザ版Google Earthです。
初期のブラウザ版Google EarthはChromeでしか利用できないという課題がありました。
Google Earthは、Native Client(NaCI)を用いてビルドされているC++アプリケーションです。
Native ClientはC/C++アプリケーションをブラウザで実行できるサンドボックス環境であり、Google Earthが公開された初期の頃はChromeのみで利用可能でした。
より多くのユーザにGoogle Earthを使ってもらうためには、Chrome以外のブラウザに対応することが求められます。そこでWebAssemblyが選ばれました。

WebAsemblyが選ばれた背景には以下のようなものがあると考えられます。

  • WebAssemblyがオープンスタンダードとして標準化され、各ブラウザの対応が進んだ
  • WebAssemblyはネイティブコードをブラウザで実行できるため、C++で実装されているGoogle Earthも実行可能である
  • WebAssemblyは負荷の大きな処理でも安定したパフォーマンスを発揮する

2.2 事例② Google Meet

Google Meet

事例②はGoogle Meetです。
ビデオ会議の機会の増加とともに、ビデオ会議におけるプライバシーの向上がGoogle Meetチームの興味の中心となりました。そこでGoole Meetでは背景にぼかしをかける機能をリリースします。この機能はMediaPipeを用いて開発されました。このときMediaPipe内で利用されていたがWebAssemblyです。
MediaPipe内では下記のような処理が行われています

Media Pipe
Google AI Blogより引用

動画の各フレームから背景を抽出してぼかしをかける処理を行うのは、ある程度負荷の大きな処理になりますが、WebAssemblyを利用すればネイティブコードに近い性能でこの機能を提供することができます。
この事例もやはりブラウザ上で重い処理を実行する目的でWebAssemblyが利用されています。

2.3 事例③AutoCAD Web App

AutoCAD

事例③ではAutoCAD Web Appを紹介します。
AutoCADはAutodesk社が公開しているブラウザ版のCADアプリケーションです。
Autodesk社ではAutoCAD、Inventor、Fuision360、Maya、3ds Maxなど数々の有名なCADやグラフィックスツールを提供しています。

AutodeskはWebAssemblyを用いることにより、C++で記述され、35年以上育てられたAutoCADをブラウザから利用できるようにしました。
一般的にCADを利用する際は数GB~数十GBのアプリケーションをインストールする必要があり、マシンスペックもある程度高いものが求められます。
WebAssemblyを用いてブラウザで使えるようにしたことで、大きなサイズのアプリケーションをインストールする必要もなく、より多くのユーザがCADを利用できるようになりました。

2.4 事例④ Unity

unity-masterbrand-black.png

事例④はUnityです。
Unityは世界中で最も利用されているゲームエンジンの1つです。(ゲームだけでなく様々な業界で利用されているのでもはやゲームエンジンと呼ぶべきではないかもしれません。。。)
Unityでは作成したゲームやアプリケーションをブラウザ向けにビルドすることができます。以前はasm.jsを用いていましたが、処理速度、メモリ効率、コードサイズ、デバッグのしやすさなどの観点からWebAssembly(WASM)へ置き換えられました。
これにより、Unityで出力したゲームやアプリケーションがより安定してブラウザ上で稼働するようになりました。

2.5 事例⑤ eBayバーコードスキャナ

WebAssembly at eBay

WebAssembly at eBay: A Real-World Use Caseより引用

事例⑤ではeBayバーコードスキャナを紹介します。
eBayの利用ユーザは商品を出品する際に商品のUPC(Universal Product Code)を入力します。
eBayのiOS/AndroidのネイティブアプリではバーコードをスキャンしてUPCを取得できましたが、Webユーザは手動でUPCを入力する必要がありました。
ユーザの利便性を高めるために、eBayはJavaScriptライブラリを用いてバーコードをスキャンする機能を実装しましたが、レスポンスが非常に悪く、故障したと勘違いするユーザもいたそうです。
このような状況を改善するため、WebAssemblyが利用されました。
WebAssemblyを用いることで安定した性能でバーコードスキャンを行うことができ、またネイティブアプリ向けに実装していたC++のライブラリも流用できました。

2.6 その他の事例

上記で紹介した事例以外にも、TensorFlow.jsOpenCVなどでもWebAssemblyが使われています。
WebAssemblyを利用しているプロジェクトの一例がmadewithwebassembly.comというサイトで紹介されているので、是非覗いてみてください。

3. WebAssemblyに関するアンケート

主にWebアプリケーションにおいてWebAssemblyは多くの課題を解決していることが事例を通して分かりました。
ここではそんなWebAssemblyに関するアンケート調査の結果を紹介します。

stateofjs.comのアンケート結果によると、2019年から2020年にかけてWebAssemblyの利用者は増加し、WebAssemblyを知らない人は減少しています。
アンケート回答者の属性はこちらに記載があり、フロントエンジニアの方が多そうです。フロントエンジニアの間ではもはやWebAssemblyについて知っていることは当たり前になりつつあると見做しても良さそうですね。

スクリーンショット 2021-12-08 9.48.16.png

State of JS そのほかの機能より引用

The State of WebAssembly 2021でも同様にWebAssemblyのアンケートを行った結果が紹介されています。
こちらのアンケート結果を引用すると、WebAssemblyで最も利用されている言語はRustであり、Rustに次いでC++となっています。言語仕様レベルでメモリ安全なRustは開発者に広く用いられている言語であり、Gabage Collectionがないこと、実行ファイルサイズが小さいことがWebAssemblyに適している理由であると分析されています。
C++はやはりその高速な処理速度から画像処理やゲーム開発などに用いられていることが多いのではないでしょうか。AutoCADやeBayの事例で紹介したように、既存のソースコードがC++で実装されていたためにそれを流用しているというケースも多そうです。

current-language.png

以下はWebAssemblyの適用場面に関するアンケート結果です。
WebAssemblyは特定の環境を対象とした技術ではありませんが、ブラウザでのアプリケーションの実行をメインのゴールとしていました。アンケート結果でも、Web開発における利用が多くなっています。
Web開発やGame開発は事例①〜⑤で紹介したような事例に似たものが多いような気がします。

ServerlessやContainerizationが上位に来ていることも興味深い結果です。
WebAssemblyはAWS Lambdaで実行することも可能であり、Serverlessというのは主にクラウド上で利用されていると考えて良いかと思います。さらにDockerやKubernetesを利用することも一般的になっているため、コンテナ内でWebAssemblyを実行しているというケースも多いのかもしれません。wasm-to-ociなどを利用してWebAssemblyをコンテナ化しているという事例もありそうです。

wasm-usage.png

4. WebAssemblyの仕組み

4.1 V-ISAとAPI

WebAssemblyは大きくVirtual Instruction Set Architecture (V-ISA:virtual ISA)WebAssembly Application Programming Interface (API)の2つの体系からなっています。

Virtual Instruction Set Aarchitecture (V-ISA:virtual ISA)

Virtual Instruction Set Aarchitectureは日本語に訳すと「仮想命令セットアーキテクチャ」です。
命令セットアーキテクチャとは、コンピュータに対して行える命令語や演算などの体系のことです。
WebAssemblyで規定されている命令セットの一覧は下記のページに記載されていますが、基本的にこれらの命令を開発者が直接記述することは殆どないかと思います。

WebAssemblyで利用する命令セットは、WebAssemblyの仮想マシンに対する命令であり、直接環境(ハードウェア)に対して命令を出すわけではありません。このためvirtualなISAと呼ばれます。

WebAssembly Application Programming Interface (API)

WebAssemblyのV-ISAは特定の環境を対象とした命令セットではありませんでした。
WebAssemblyからの命令を受け付け、環境ごとの差異を吸収するものがAPI(ABI)となります。

APIはランタイムに実装されており、WebAssemblyはランタイム上で実行します。
wasmtimeというランタイムを見てみると、下記の通りLinux、MacOS、Windowsなど、環境ごとに異なる実行ファイルが提供されていることがわかります。

ランタイム

下図はランタイムが環境差異を吸収していることを表す概念図です。
繰り返しになりますが、LinuxやWindows、あるいはブラウザなども含めて環境差異はランタイムが吸収します。またランタイムがAPIを実装していることで、WebAssemblyは様々な環境で同じコードを用いて実行できるようになります。

env.jpg

4.2 WebAssemblyが実行されるまで

WebAssemblyが実行されるまでの流れを下図に示します。
各言語のソースコードはコンパイラによりWASMファイル(WASMバイトコード)へ変換されます。
C/C++であればEmscripten、Rustであればwasm-pack、goであればビルトインのコンパイラなどを使用します。
WASMバイトコードはランタイム上で実行されます。ランタイムにも様々な選択肢がありますが、有名なものではwasmerwasmtimeLucet、などが挙げられます。
ランタイムによりWASMバイトコードは各環境に適した実行ファイル(バイナリコード)に変換され、実行されます。
WASMバイトコードからバイナリコードへの変換方法にもJIT(Just-in-Time)やAOT(Ahead-of-Time)などいくつか方法がありますがここでは詳細は割愛します。これについてはブロックチェーンで使われるWebAssembly Runtimeでわかりやすく解説されているので、こちらをご参照ください。

wasm_flow.jpg

まとめ・所感

この記事ではWebAssemblyとは何か、何ができて、どういう状況で使えるのかをまとめました。
やはりブラウザで画像処理やゲームなどの高負荷処理を実行する際にはWebAssembly使えるなーというのが感想です。
逆にサーバサイドでしか使わないアプリケーションをあえてWebAssemblyとして実行するケースがあるのかは気になるので、引き続き調査を続けたいと思います。

今回の調査を通して、WebAssemblyとは命令形式(命令セット)であること、環境差異はランタイムにより吸収されていることがわかりました。
ランタイムでどのようにバイナリコードへコンパイルされるかまでは詳しく調べられませんでしたが、WebAssemblyが実行されるまでのおよその流れを掴むことができました。

本記事内では技術的なトピックはほとんど扱いませんでしたが、さくっとWebAssemblyを試してみたいという方のために、Mozillaからwebassembly.studioというサイトが公開されています。

webassembly.studio

参考資料

108
43
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
108
43

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?