ホームページ バックエンド開発 Golang Wasm コンポーネント モデルと慣用的な codegen

Wasm コンポーネント モデルと慣用的な codegen

Dec 22, 2024 pm 02:39 PM

The Wasm Component Model and idiomatic codegen

Arcjet には、WebAssembly と Security as Code SDK がバンドルされています。これは、開発者が PII 検出やボット検出などの一般的なセキュリティ機能をコードに直接実装するのに役立ちます。ロジックの多くは Wasm に埋め込まれており、ネイティブに近いパフォーマンスを備えた安全なサンドボックスを提供し、ローカルファースト セキュリティに関する私たちの哲学の一部です。

プラットフォーム間で同じコードを実行できる機能も、JavaScript から他の技術スタックへのサポートを構築する際に役立ちますが、言語間で変換するには重要な抽象化が必要です (Wasm は Rust からコンパイルされています)。

WebAssembly コンポーネント モデル はこれを可能にする強力な構造ですが、その構造はそれを囲む実装とツールによってのみ優れています。コンポーネント モデルの場合、これはホスト (WebAssembly コンポーネント モデルを実行する環境) とゲスト (任意の言語で記述され、コンポーネント モデルにコンパイルされた WebAssembly モジュール。この場合は Rust) のコード生成で最も明らかです。

コンポーネント モデルは、主に型、関数、インポート、エクスポートで構成されるホストとゲスト間の通信用の言語を定義します。幅広い言語を定義しようとしていますが、バリアント、タプル、リソースなどの一部の型は、特定の汎用プログラミング言語に存在しない可能性があります。

ツールがこれらの言語のいずれかのコードを生成しようとする場合、作成者は多くの場合、コンポーネント モデル タイプをその汎用言語にマッピングするために創造性を発揮する必要があります。たとえば、JS バインディングの生成には jco を使用します。これにより、{ タグ: 文字列、値: 文字列 } の形式の JavaScript オブジェクトを使用してバリアントが実装されます。結果には特殊なケースもあります<_, _>エラーのバリアントが Error に変換されてスローされるタイプ。

この投稿では、Wasm コンポーネント モデルが言語間の統合をどのように可能にするか、ホストとゲストのコード生成の複雑さ、Go などの言語で慣用的なコードを実現するために行うトレードオフについて説明します。

Go 用のホスト コード生成

Arcjet では、Go プログラミング言語で書かれたホスト用のコードを生成するツールを構築する必要がありました。私たちの SDK はすべてをローカルで分析しようとしますが、それが常に可能であるとは限らないため、Go で書かれた API を用意し、追加のメタデータでローカルの決定を強化します。

Go は設計上、非常に最小限の構文と型システムを備えています。ごく最近までジェネリック医薬品さえありませんでしたが、依然として重大な制限があります。これにより、コンポーネント モデルから Go へのコード生成がさまざまな点で複雑になります。

たとえば、次のような結果を生成できます<_, _>として:

type Result[V any] struct {
    value V
    err error
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

ただし、エラー位置に提供できる型が制限されます。したがって、次のようにコード生成する必要があります:

type Result[V any] struct {
    value V
    err error
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

これは機能しますが、他の慣用的な Go で使用すると面倒になります。Go では、上で定義した Result タイプと同じセマンティクスを示すために val, err := doSomething() 規則がよく使用されます。

さらに、この Result の構築は面倒です: Result[int, string]{value: 1, err: ""}。 Result タイプを提供する代わりに、Go ユーザーが生成されたバインディングを自然に利用できるように、慣用的なパターンに一致させたいと考えています。

慣用的マッピングと直接マッピング

コードは、言語にとってより自然に感じられるように生成することも、コンポーネント モデル タイプへのより直接的なマッピングにすることもできます。どちらのオプションも 100% のユースケースに適合するわけではないため、どちらが最も合理的であるかを判断するのはツールの作成者次第です。

Arcjet ツールの場合、オプションとして慣用的な Go アプローチを選択しました<_>結果<_, _>これらの型は、それぞれ val, ok := doSomething() および val, err := doSomething() にマップされます。バリアントの場合、各バリアントが実装する必要がある次のようなインターフェイスを作成します。

type Result[V any, E any] struct {
    value V
    err E
}
ログイン後にコピー
ログイン後にコピー

これにより、型の安全性と不必要なラッピングのバランスが取れています。もちろん、ラッピングが必要な状況もありますが、それはエッジケースとして処理できます。

開発者は、非慣用的なパターンに苦労し、冗長で保守性の低いコードにつながる可能性があります。確立された規則を使用すると、コードがより親しみやすくなりますが、実装には追加の作業が必要になります。

コードベースを移動する際に何が起こるかを理解できるように、摩擦を最小限に抑え、チームにとって作業を容易にする慣用的な方法を採用することにしました。

呼び出し規約

ツール作成者が行う必要がある最大の決定の 1 つは、バインディングの呼び出し規約です。これには、インポートをいつどのようにコンパイルするか、Wasm モジュールをセットアップ中またはインスタンス化中、およびクリーンアップ中にコンパイルするかどうかの決定が含まれます。

Arcjet コードベースでは、パフォーマンスを最適化するためにファクトリ/インスタンス パターンを選択しました。 WebAssembly モジュールのコンパイルにはコストがかかるため、NewBotFactory() コンストラクターで 1 回だけ実行します。後続の Instantiate() 呼び出しは高速かつ安価であり、実稼働ワークロードでの高スループットが可能になります。

type BotConfig interface {
    isBotConfig()
}

func (AllowedBotConfig) isBotConfig() {}

func (DeniedBotConfig) isBotConfig() {}
ログイン後にコピー

消費者は NewBotFactory(ctx) を呼び出してこの BotFactory を 1 回構築し、それを使用して Instantiate メソッド経由で複数のインスタンスを作成します。

func NewBotFactory(
    ctx context.Context,
) (*BotFactory, error) {
    runtime := wazero.NewRuntime(ctx)

    // ... Imports are compiled here if there are any

    // Compiling the module takes a LONG time, so we want to do it once and hold
    // onto it with the Runtime
    module, err := runtime.CompileModule(ctx, wasmFileBot)
    if err != nil {
            return nil, err
    }

    return &BotFactory{runtime, module}, nil
}
ログイン後にコピー

ファクトリを構築するときに runtime.CompileModule() を使用するように、モジュールがすでにコンパイルされている場合、インスタンス化は非常に高速です。

BotInstance には、コンポーネント モデル定義からエクスポートされた関数があります。

func (f *BotFactory) Instantiate(ctx context.Context) (*BotInstance, error) {
    if module, err := f.runtime.InstantiateModule(ctx, f.module, wazero.NewModuleConfig()); err != nil {
            return nil, err
    } else {
            return &BotInstance{module}, nil
    }
}
ログイン後にコピー

通常、BotInstance を使用した後は、メモリ リークが発生していないことを確認するために、BotInstance をクリーンアップする必要があります。このために、Close 関数を提供します。

func (i *BotInstance) Detect(
    ctx context.Context,
    request string,
    options BotConfig,
) (BotResult, error) {
   // ... Lots of generated code for binding to Wazero
}
ログイン後にコピー

BotFactory 全体をクリーンアップしたい場合は、それを閉じることもできます:

type Result[V any] struct {
    value V
    err error
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

これらの API をすべてまとめて、この WebAssembly モジュールの関数を呼び出すことができます。

type Result[V any, E any] struct {
    value V
    err E
}
ログイン後にコピー
ログイン後にコピー

このファクトリーとインスタンスの構築パターンでは使用するコードが多くなりますが、Arcjet サービスのホット パスで可能な限り多くのパフォーマンスを達成するために選択されました。

コンパイル コストを前倒しすることで、Arcjet サービスのホット パス (レイテンシーが最も重要な場所) でのリクエスト処理が可能な限り効率的になるようにします。このトレードオフにより、初期化コードは多少複雑になりますが、リクエストごとのオーバーヘッドが大幅に減少するというメリットがあります。トレードオフについての説明を参照してください

トレードオフ

2 つ以上の言語を統合する必要がある場合は常に、ネイティブ FFI を使用する かコンポーネント モデルを使用するかにかかわらず、トレードオフを行う必要があります。

この投稿では、アークジェットで遭遇したいくつかの課題と、その決定の背後にある理由について説明しました。コンポーネント モデルや WIT などの同じプリミティブのセットを全員が構築すると、wit-bindgenwit-component などの高品質のプリミティブの同じセットを活用できます。 を使用して、あらゆるユースケースに適したツールを構築します。これが、標準に向けた取り組みがすべての人に役立つ理由です。

WebAssembly コンポーネント モデルは、言語間の統合のための強力な抽象化を提供しますが、その型を Go などの言語に変換すると、微妙な設計上の課題が生じます。ファクトリ/インスタンス パターンの使用など、慣用的なパターンを選択し、パフォーマンスを選択的に最適化することで、効率を維持しながら自然な開発者エクスペリエンスを提供できます。

コンポーネント モデルに関するツールが進化するにつれて、これらの統合をさらに簡素化する、より洗練されたコード生成アプローチが期待できます。

以上がWasm コンポーネント モデルと慣用的な codegenの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Golang vs. Python:パフォーマンスとスケーラビリティ Golang vs. Python:パフォーマンスとスケーラビリティ Apr 19, 2025 am 12:18 AM

Golangは、パフォーマンスとスケーラビリティの点でPythonよりも優れています。 1)Golangのコンピレーションタイプの特性と効率的な並行性モデルにより、高い並行性シナリオでうまく機能します。 2)Pythonは解釈された言語として、ゆっくりと実行されますが、Cythonなどのツールを介してパフォーマンスを最適化できます。

Golang and C:Concurrency vs. Raw Speed Golang and C:Concurrency vs. Raw Speed Apr 21, 2025 am 12:16 AM

Golangは並行性がCよりも優れていますが、Cは生の速度ではGolangよりも優れています。 1)Golangは、GoroutineとChannelを通じて効率的な並行性を達成します。これは、多数の同時タスクの処理に適しています。 2)Cコンパイラの最適化と標準ライブラリを介して、極端な最適化を必要とするアプリケーションに適したハードウェアに近い高性能を提供します。

ゴーを始めましょう:初心者のガイド ゴーを始めましょう:初心者のガイド Apr 26, 2025 am 12:21 AM

goisidealforforbeginnersandsutable forcloudnetworkservicesduetoitssimplicity、andconcurrencyfeatures.1)installgofromtheofficialwebsiteandverify with'goversion'.2)

Golang vs. C:パフォーマンスと速度の比較 Golang vs. C:パフォーマンスと速度の比較 Apr 21, 2025 am 12:13 AM

Golangは迅速な発展と同時シナリオに適しており、Cは極端なパフォーマンスと低レベルの制御が必要なシナリオに適しています。 1)Golangは、ごみ収集と並行機関のメカニズムを通じてパフォーマンスを向上させ、高配列Webサービス開発に適しています。 2)Cは、手動のメモリ管理とコンパイラの最適化を通じて究極のパフォーマンスを実現し、埋め込みシステム開発に適しています。

Golangの影響:速度、効率、シンプルさ Golangの影響:速度、効率、シンプルさ Apr 14, 2025 am 12:11 AM

speed、効率、およびシンプル性をspeedsped.1)speed:gocompilesquilesquicklyandrunseffictient、理想的なlargeprojects.2)効率:等系dribribraryreducesexexternaldedenciess、開発効果を高める3)シンプルさ:

Golang vs. Python:重要な違​​いと類似点 Golang vs. Python:重要な違​​いと類似点 Apr 17, 2025 am 12:15 AM

GolangとPythonにはそれぞれ独自の利点があります。Golangは高性能と同時プログラミングに適していますが、PythonはデータサイエンスとWeb開発に適しています。 Golangは同時性モデルと効率的なパフォーマンスで知られていますが、Pythonは簡潔な構文とリッチライブラリエコシステムで知られています。

GolangとC:パフォーマンスのトレードオフ GolangとC:パフォーマンスのトレードオフ Apr 17, 2025 am 12:18 AM

GolangとCのパフォーマンスの違いは、主にメモリ管理、コンピレーションの最適化、ランタイム効率に反映されています。 1)Golangのゴミ収集メカニズムは便利ですが、パフォーマンスに影響を与える可能性があります。

パフォーマンスレース:ゴラン対c パフォーマンスレース:ゴラン対c Apr 16, 2025 am 12:07 AM

GolangとCにはそれぞれパフォーマンス競争において独自の利点があります。1)Golangは、高い並行性と迅速な発展に適しており、2)Cはより高いパフォーマンスと微細な制御を提供します。選択は、プロジェクトの要件とチームテクノロジースタックに基づいている必要があります。

See all articles