[Python][WASI] Python から WebAssembly を呼び出し

  • 2022年9月18日
  • 2022年9月18日
  • Python
  • 9View
  • 0件

はじめに

WebAssembly というのは、WebAP のフロントエンド開発において高速さと堅牢さを実現するために生み出された技術です。
これを利用して、WebAP 以外でも WebAssembly を利用してポータビリティを向上させるための技術が WASI (WebAssembly System Interface) です。

WASI はまだ発展途上ではありますが、wasmtime という WASI の参照実装が開発されています。
これを利用して Python から WebAssembly の呼び出しを行います。

Python から WebAssembly 呼び出し

動作環境

  • Windows 11
  • WSL Ubuntu 20.04
  • Python 3.8.10
  • wasmtime 0.40.0

事前準備

WSL ディストリビューションの複製(非必須)

お試しで実行する場合は WSL Ubuntu イメージを複製しておくのがお勧めです。
本手順は必須ではありません。

各種インストール

初めに、Ubuntu パッケージを最新化しておきます。

$ sudo apt update
$ sudo apt upgrade

python パッケージをインストールするための pip をインストールします。

$ sudo apt install python3-pip

次に、pip から wasmtime をインストールします。

$ pip install wasmtime

WebAssembly コード

今回使用する WebAssembly のサンプルコードです。

(module
  (func (export "add_int")
    (param $value_1 i32) (param $value_2 i32)
    (result i32)
    local.get $value_1
    local.get $value_2
    i32.add
  )
)

2つの整数を足し合わせる add_int メソッドを定義しています。
3行目の param 句が引数を定義しています。
4行目の result で戻り値の型を指定しています。

5~6行目の local.get では、それぞれの引数の値をスタックに積んでいます。
7行目の i32.add でスタックから整数を2つポップして足し算し、この結果を再度スタックに積んでいます。
最終的にスタックに残った整数値が result として返却されます。

Python コード

シンプルに呼び出し

Python コードから WebAssembly を呼び出すには2つ手法があります。
まずはシンプルな呼び出し方法です。

import wasmtime.loader  # noqa
import sample  # type: ignore

print(sample.add_int(3, 5))

1行目で wasmtime.loader をインポートしています。
これをインポートすることで、WebAssembly の呼び出しを簡略化することができます。
flake8 より未使用 import の警告が発生するため # noqa のコメントを挿入しています。

2行目では WebAssembly をインポートしています。
今回は sample.wat としてファイルを保存しましたので、ここから拡張子を除いた sample をインポートします。
Pylance からインポートの解決失敗の警告が発生するため、これを無視する目的で # type: ignore のコメントを挿入しています。

メインのコードは4行目のみです。
sample.add_int を呼び出し、3 + 5 の演算をさせます。

$ python3 main_simple.py 
8

冗長に呼び出し

次に冗長な呼び出し方法です。
カスタマイズが必要なケースでは、こちらの手法を用いることになります。

なお、下記のページに公式ドキュメントがありますが、記事執筆時点(2022/09/18)ではドキュメントが古いようで、各種仕様が正しくありません。

wasmtime 0.40.0 で動作するよう、適宜見直しをしています。

import wasmtime

store = wasmtime.Store()
module = wasmtime.Module.from_file(store.engine, "sample.wat")
instance = wasmtime.Instance(store, module, [])
add_int = instance.exports(store)["add_int"]
print(add_int(store, 3, 5))

実行結果はシンプルな呼び出し方法と同じです。
3 + 5 の結果が返却されます。

$ python3 main_verbose.py 
8

参考書籍