- Go 1.24でWebAssembly(Wasm)関連機能が拡張
go:wasmexport ディレクティブが追加され、Wasmモジュールの外部からGo関数を呼び出せるようになった
- WASI向けの「reactor」ビルドモードにも対応し、長時間アクティブな状態でコードを実行できるようになった
- これにより、Wasm環境でGoアプリケーションをより柔軟に拡張できる可能性が開かれた
WebAssembly and the WebAssembly System Interface
- WebAssemblyは、Webブラウザで高性能な低レベルコードを実行するために作られたバイナリフォーマット
- 現在はブラウザ外でも幅広く活用されており、WebAssembly System Interface(WASI)を通じてシステムリソースと相互作用できる
- Goはバージョン1.11で js/wasm ポートによりWasmコンパイルをサポートし始め、1.21では新しい
GOOS=wasip1 ポートによって WASI Preview 1 のシステムコールAPIを対象とする新たなポートを追加
go:wasmexport を使ったGo関数のWasmエクスポート
- Go 1.24で新たに追加された
go:wasmexport ディレクティブにより、Go関数をWasmモジュール外部から呼び出せるよう export として公開できる
- 例:
//go:wasmexport add のように宣言して関数を書けば、Wasmホストがその関数を呼び出せる
- これはcgoの
export ディレクティブに似ているが、よりシンプルなメカニズムで実装されている
Building a WASI Reactor
- WASI の「reactor」は、継続的に動作し、イベントやリクエストに応答できるWebAssemblyモジュールを意味する
- Go 1.24では
-buildmode=c-shared オプションを使って WASI reactor ビルドをサポート
- このビルドフラグはリンカに対し、_start 関数(コマンドモジュールのエントリポイント)を生成せず、代わりに _initialize 関数を生成するよう指示する
- reactor は
_initialize 関数によって初期化され、main 関数の代わりにまずこの関数を呼び出す必要がある
- Wazero のようなランタイムと組み合わせると、
_initialize 呼び出し後に export された関数を必要なだけ再呼び出しできる
- この方式は、アプリケーションのプラグインや拡張機構としてWasmを活用する環境で有用
ホストとクライアント間のリッチな型サポート
- Go 1.24では
go:wasmimport で呼び出される関数の引数・戻り値型に対する制約が緩和
- たとえば、bool、string、int32 ポインタ、構造体ポインタなどを渡せる
- ただし、64ビット環境と32ビット環境の違いなどにより、依然として制限は存在する
- これにより、Go Wasmアプリケーションをより自然かつ便利に書けるようになり、不必要な型変換を排除できる
制限事項
- Wasmは並列処理のないシングルスレッドアーキテクチャ
go:wasmexport 関数は新しいゴルーチンを生成できるが、バックグラウンドゴルーチンを生成する関数は、go:wasmexport 関数が戻った後、GoベースのWasmモジュールが再度呼び出されるまで実行を継続しない
- 一部の型制約は緩和されたが、依然として
go:wasmimport および go:wasmexport 関数とともに使用できる型には制限がある
- ポインタを含む複合型の受け渡しには、まだ制約が存在する
結論
- Go 1.24の WASI reactor ビルドと
go:wasmexport 機能の追加は、GoのWasmエコシステムを大きく広げる改善
- これにより開発者は、より多様なGoベースのWasmアプリケーションを作れるようになり、WasmエコシステムにおけるGoの新たな可能性を開く
3件のコメント
Wasm/gcが広く導入される前は、gcのない言語でwasmターゲットを開発するのがよさそうです
Go 1.24 リリースでは簡単に触れられているだけですが、はるかに重要なアップデートですね。
Hacker Newsの意見
Goで生成されたWASMバイナリには非常に大きいという問題がある。TinyGoはこれを克服するが、コンパイル速度が遅く、ライブラリ選定にも注意が必要だ。両方を乗り越えるにはかなりの忍耐が必要になる
驚くべきことだ。覚えておくべき点:
Go 1.24以前でも、Go関数をJSにエクスポートすることは可能ではなかったか、よく覚えていない。以前、JSからエクスポートされたGo関数を問題なく呼び出せた記憶がある
mainパッケージで大文字で始まるすべての関数をエクスポートするほうが、より「Goらしい」と思う。エクスポートは通常言語の仕組みとして機能するので、小文字で始まるものを明示的に指定するときだけコンパイラディレクティブを使うのがよい
WASMコンポーネントモデルとの連携についての言及がない
GoとWASMのガベージコレクションがどう動作するのか気になる
強い型付けと優れたWASMサポートを備えた低レベル言語があればよいのに
ホストプログラムで実行中のWASMモジュールをどうデバッグするのか気になる
より多くのWASM機能を求める動きが、若いエコシステムに取り返しのつかない害を与えるのではないかと心配している。GoがWASMに追加した機能の大半は、コンポーネントモデルの提案がすでにマージされていればネイティブに実現できたはずだ