Heim Backend-Entwicklung Golang Das Wasm-Komponentenmodell und das idiomatische Codegen

Das Wasm-Komponentenmodell und das idiomatische Codegen

Dec 22, 2024 pm 02:39 PM

The Wasm Component Model and idiomatic codegen

Arcjet bündelt WebAssembly mit unserem Security-as-Code-SDK. Dies hilft Entwicklern, gängige Sicherheitsfunktionen wie PII-Erkennung und Bot-Erkennung direkt in ihren Code zu implementieren. Ein Großteil der Logik ist in Wasm eingebettet, was uns eine sichere Sandbox mit nahezu nativer Leistung bietet und Teil unserer Philosophie rund um Local-First-Sicherheit ist.

Die Möglichkeit, denselben Code plattformübergreifend auszuführen, ist ebenfalls hilfreich, da wir die Unterstützung von JavaScript auf andere Tech-Stacks ausbauen, aber für die Übersetzung zwischen Sprachen ist eine wichtige Abstraktion erforderlich (unser Wasm wird aus Rust kompiliert).

Das WebAssembly Component Model ist das leistungsstarke Konstrukt, das dies ermöglicht, aber ein Konstrukt kann nur so gut sein wie die Implementierungen und Tools, die es umgeben. Beim Komponentenmodell zeigt sich dies am deutlichsten in der Codegenerierung für Hosts (Umgebungen, die das WebAssembly-Komponentenmodell ausführen) und Gäste (WebAssembly-Module, die in einer beliebigen Sprache geschrieben und zum Komponentenmodell kompiliert wurden; in unserem Fall Rust).

Das Komponentenmodell definiert eine Sprache für die Kommunikation zwischen Hosts und Gästen, die hauptsächlich aus Typen, Funktionen, Importen und Exporten besteht. Es wird versucht, eine breite Sprache zu definieren, aber einige Typen, wie Varianten, Tupel und Ressourcen, existieren möglicherweise nicht in einer bestimmten Programmiersprache für allgemeine Zwecke.

Wenn ein Tool versucht, Code für eine dieser Sprachen zu generieren, müssen die Autoren oft kreativ werden, um Komponentenmodelltypen dieser Allzwecksprache zuzuordnen. Zum Beispiel verwenden wir jco zum Generieren von JS-Bindungen und dies implementiert Varianten mithilfe eines JavaScript-Objekts in der Form { tag: string, value: string }. Es gibt sogar einen Sonderfall für das Ergebnis <_, _> Geben Sie ein, bei dem die Fehlervariante in einen Fehler umgewandelt und ausgelöst wird.

In diesem Beitrag wird untersucht, wie das Wasm-Komponentenmodell sprachübergreifende Integrationen ermöglicht, wie komplex die Codegenerierung für Hosts und Gäste ist und welche Kompromisse wir eingehen, um idiomatischen Code in Sprachen wie Go zu erreichen.

Hostcode-Generierung für Go

Bei Arcjet mussten wir ein Tool entwickeln, um Code für Hosts zu generieren, der in der Programmiersprache Go geschrieben wurde. Obwohl unser SDK versucht, alles lokal zu analysieren, ist das nicht immer möglich und deshalb haben wir eine in Go geschriebene API, die lokale Entscheidungen mit zusätzlichen Metadaten ergänzt.

Go hat von Natur aus ein sehr minimales Syntax- und Typsystem. Bis vor kurzem gab es noch nicht einmal Generika, und es gibt immer noch erhebliche Einschränkungen. Dies macht die Codegenerierung vom Component Model to Go in vielerlei Hinsicht komplex.

Zum Beispiel könnten wir ein Ergebnis generieren<_, _> als:

type Result[V any] struct {
    value V
    err error
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Dies schränkt jedoch den Typ ein, der an der Fehlerposition bereitgestellt werden kann. Wir müssten es also wie folgt codegenerieren:

type Result[V any] struct {
    value V
    err error
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Dies funktioniert, wird aber mit anderen idiomatischen Go-Elementen umständlich zu verwenden, da diese häufig die Konvention val, err := doSomething() verwenden, um die gleiche Semantik wie der oben definierte Ergebnistyp anzugeben.

Außerdem ist die Erstellung dieses Ergebnisses umständlich: Result[int, string]{value: 1, err: ""}. Anstatt den Ergebnistyp bereitzustellen, möchten wir wahrscheinlich idiomatische Muster abgleichen, damit Go-Benutzer sich natürlich fühlen, wenn sie unsere generierten Bindungen nutzen.

Idiomatische vs. direkte Zuordnung

Code kann so generiert werden, dass er sich natürlicher für die Sprache anfühlt, oder es kann eine direktere Zuordnung zu den Komponentenmodelltypen erfolgen. Keine der Optionen passt zu 100 % der Anwendungsfälle, daher liegt es an den Tool-Autoren, zu entscheiden, welche am sinnvollsten ist.

Für die Arcjet-Werkzeuge haben wir den idiomatischen Go-Ansatz für die Option<_> gewählt. und result<_, _> Typen, die jeweils auf val, ok := doSomething() und val, err := doSomething() abgebildet werden. Für Varianten erstellen wir eine Schnittstelle, die jede Variante implementieren muss, wie zum Beispiel:

type Result[V any, E any] struct {
    value V
    err E
}
Nach dem Login kopieren
Nach dem Login kopieren

Dies schafft eine gute Balance zwischen Typsicherheit und unnötigem Umwickeln. Natürlich gibt es Situationen, in denen eine Umhüllung erforderlich ist, aber diese können als Randfälle behandelt werden.

Entwickler haben möglicherweise Probleme mit nicht idiomatischen Mustern, was zu ausführlichem und weniger wartbarem Code führt. Durch die Verwendung etablierter Konventionen fühlt sich der Code vertrauter an, die Implementierung erfordert jedoch etwas mehr Aufwand.

Wir haben uns für den idiomatischen Weg entschieden, um Reibungsverluste zu minimieren und es unserem Team einfacher zu machen, damit wir wissen, was uns erwartet, wenn wir uns in der Codebasis bewegen.

Aufrufe zu Konventionen

Eine der wichtigsten Entscheidungen, die Tool-Autoren treffen müssen, ist die Aufrufkonvention der Bindungen. Dazu gehört die Entscheidung, wie/wann Importe kompiliert werden, ob das Wasm-Modul während der Einrichtung oder Instanziierung kompiliert wird, und die Bereinigung.

In der Arcjet-Codebasis haben wir das Fabrik-/Instanzmuster ausgewählt, um die Leistung zu optimieren. Das Kompilieren eines WebAssembly-Moduls ist teuer, daher führen wir es einmal im NewBotFactory()-Konstruktor durch. Nachfolgende Instantiate()-Aufrufe sind dann schnell und kostengünstig und ermöglichen einen hohen Durchsatz bei Produktions-Workloads.

type BotConfig interface {
    isBotConfig()
}

func (AllowedBotConfig) isBotConfig() {}

func (DeniedBotConfig) isBotConfig() {}
Nach dem Login kopieren

Verbraucher erstellen diese BotFactory einmal, indem sie NewBotFactory(ctx) aufrufen, und verwenden sie, um über die Instantiate-Methode mehrere Instanzen zu erstellen.

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
}
Nach dem Login kopieren

Die Instanziierung erfolgt sehr schnell, wenn das Modul bereits kompiliert wurde, wie wir es mit runtime.CompileModule() beim Erstellen der Factory tun.

Die BotInstance verfügt über Funktionen, die aus der Komponentenmodelldefinition exportiert wurden.

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
    }
}
Nach dem Login kopieren

Im Allgemeinen möchten wir eine BotInstance nach der Verwendung bereinigen, um sicherzustellen, dass kein Speicher verloren geht. Hierfür stellen wir die Close-Funktion zur Verfügung.

func (i *BotInstance) Detect(
    ctx context.Context,
    request string,
    options BotConfig,
) (BotResult, error) {
   // ... Lots of generated code for binding to Wazero
}
Nach dem Login kopieren

Wenn Sie die gesamte BotFactory bereinigen möchten, kann diese auch geschlossen werden:

type Result[V any] struct {
    value V
    err error
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Wir können alle diese APIs zusammenfügen, um Funktionen in diesem WebAssembly-Modul aufzurufen:

type Result[V any, E any] struct {
    value V
    err E
}
Nach dem Login kopieren
Nach dem Login kopieren

Dieses Muster der Fabrik- und Instanzkonstruktion erfordert mehr Code zur Verwendung, wurde jedoch ausgewählt, um in den Hot-Paths des Arcjet-Dienstes so viel Leistung wie möglich zu erzielen.

Durch die Vorabbelastung der Kompilierungskosten stellen wir sicher, dass in den Hot Paths des Arcjet-Dienstes – wo die Latenz am wichtigsten ist – die Anforderungsbearbeitung so effizient wie möglich ist. Dieser Kompromiss erhöht zwar die Komplexität des Initialisierungscodes, zahlt sich jedoch durch einen wesentlich geringeren Overhead pro Anfrage aus – siehe unsere Diskussion der Kompromisse.

Kompromisse

Jedes Mal, wenn wir zwei oder mehr Sprachen integrieren müssen, ist dies voller Kompromisse, die eingegangen werden müssen – sei es mit nativem FFI oder dem Komponentenmodell.

In diesem Beitrag wurden einige der Herausforderungen besprochen, mit denen wir bei Arcjet konfrontiert waren, und die Gründe für unsere Entscheidungen. Wenn wir alle auf demselben Satz an Grundelementen wie dem Komponentenmodell und WIT aufbauen, können wir alle denselben Satz hochwertiger Grundelemente wie wit-bindgen oder wit-component nutzen und erstellen Sie Werkzeuge, die für jeden Anwendungsfall geeignet sind. Deshalb hilft die Arbeit an Standards allen.

Das WebAssembly-Komponentenmodell bietet eine leistungsstarke Abstraktion für die sprachübergreifende Integration, aber die Übersetzung seiner Typen in Sprachen wie Go bringt subtile Designherausforderungen mit sich. Durch die Auswahl idiomatischer Muster und die selektive Optimierung der Leistung – beispielsweise durch die Verwendung eines Fabrik-/Instanzmusters – können wir ein natürliches Entwicklererlebnis bieten und gleichzeitig die Effizienz aufrechterhalten.

Während sich die Tools rund um das Komponentenmodell weiterentwickeln, können wir uns auf verfeinerte Codegen-Ansätze freuen, die diese Integrationen weiter vereinfachen.

Das obige ist der detaillierte Inhalt vonDas Wasm-Komponentenmodell und das idiomatische Codegen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

Video Face Swap

Video Face Swap

Tauschen Sie Gesichter in jedem Video mühelos mit unserem völlig kostenlosen KI-Gesichtstausch-Tool aus!

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Golangs Zweck: Aufbau effizienter und skalierbarer Systeme Golangs Zweck: Aufbau effizienter und skalierbarer Systeme Apr 09, 2025 pm 05:17 PM

Go Language funktioniert gut beim Aufbau effizienter und skalierbarer Systeme. Zu den Vorteilen gehören: 1. hohe Leistung: Kompiliert in den Maschinencode, schnelle Laufgeschwindigkeit; 2. gleichzeitige Programmierung: Vereinfachen Sie Multitasking durch Goroutinen und Kanäle; 3. Einfachheit: präzise Syntax, Reduzierung der Lern- und Wartungskosten; 4. plattform: Unterstützt die plattformübergreifende Kompilierung, einfache Bereitstellung.

Golang und C: Parallelität gegen Rohgeschwindigkeit Golang und C: Parallelität gegen Rohgeschwindigkeit Apr 21, 2025 am 12:16 AM

Golang ist in Gleichzeitigkeit besser als C, während C bei Rohgeschwindigkeit besser als Golang ist. 1) Golang erreicht durch Goroutine und Kanal eine effiziente Parallelität, die zum Umgang mit einer großen Anzahl von gleichzeitigen Aufgaben geeignet ist. 2) C über Compiler -Optimierung und Standardbibliothek bietet es eine hohe Leistung in der Nähe der Hardware, die für Anwendungen geeignet ist, die eine extreme Optimierung erfordern.

Das Performance -Rennen: Golang gegen C. Das Performance -Rennen: Golang gegen C. Apr 16, 2025 am 12:07 AM

Golang und C haben jeweils ihre eigenen Vorteile bei Leistungswettbewerben: 1) Golang ist für eine hohe Parallelität und schnelle Entwicklung geeignet, und 2) C bietet eine höhere Leistung und eine feinkörnige Kontrolle. Die Auswahl sollte auf Projektanforderungen und Teamtechnologie -Stack basieren.

Golang gegen Python: Leistung und Skalierbarkeit Golang gegen Python: Leistung und Skalierbarkeit Apr 19, 2025 am 12:18 AM

Golang ist in Bezug auf Leistung und Skalierbarkeit besser als Python. 1) Golangs Kompilierungseigenschaften und effizientes Parallelitätsmodell machen es in hohen Parallelitätsszenarien gut ab. 2) Python wird als interpretierte Sprache langsam ausgeführt, kann aber die Leistung durch Tools wie Cython optimieren.

Golang gegen Python: Schlüsselunterschiede und Ähnlichkeiten Golang gegen Python: Schlüsselunterschiede und Ähnlichkeiten Apr 17, 2025 am 12:15 AM

Golang und Python haben jeweils ihre eigenen Vorteile: Golang ist für hohe Leistung und gleichzeitige Programmierung geeignet, während Python für Datenwissenschaft und Webentwicklung geeignet ist. Golang ist bekannt für sein Parallelitätsmodell und seine effiziente Leistung, während Python für sein Ökosystem für die kurze Syntax und sein reiches Bibliothek bekannt ist.

C und Golang: Wenn die Leistung von entscheidender Bedeutung ist C und Golang: Wenn die Leistung von entscheidender Bedeutung ist Apr 13, 2025 am 12:11 AM

C eignet sich besser für Szenarien, in denen eine direkte Kontrolle der Hardware -Ressourcen und hohe Leistungsoptimierung erforderlich ist, während Golang besser für Szenarien geeignet ist, in denen eine schnelle Entwicklung und eine hohe Parallelitätsverarbeitung erforderlich sind. 1.Cs Vorteil liegt in den nahezu Hardware-Eigenschaften und hohen Optimierungsfunktionen, die für leistungsstarke Bedürfnisse wie die Spieleentwicklung geeignet sind. 2. Golangs Vorteil liegt in seiner präzisen Syntax und der natürlichen Unterstützung, die für die Entwicklung einer hohen Parallelitätsdienste geeignet ist.

Golangs Auswirkungen: Geschwindigkeit, Effizienz und Einfachheit Golangs Auswirkungen: Geschwindigkeit, Effizienz und Einfachheit Apr 14, 2025 am 12:11 AM

GoimpactsDevelopmentPositivyThroughSpeed, Effizienz und DiasMlitication.1) Geschwindigkeit: Gocompilesquickandrunseffiction, idealforlargeProjects

Golang und C: Die Kompromisse bei der Leistung Golang und C: Die Kompromisse bei der Leistung Apr 17, 2025 am 12:18 AM

Die Leistungsunterschiede zwischen Golang und C spiegeln sich hauptsächlich in der Speicherverwaltung, der Kompilierungsoptimierung und der Laufzeiteffizienz wider. 1) Golangs Müllsammlung Mechanismus ist praktisch, kann jedoch die Leistung beeinflussen.

See all articles