WebAssembly: possibili futuri

Scrivo questo articolo dopo aver visto all’evento Build 2022 il bellissimo intevento di Steve Sanderson su alcuni scenari futuribili di WebAssembly.

Come sapete sono molto appassionato di Blazor, e una delle due varianti utilizza appunto queste tecnologia.

Scrivo questo articolo dopo aver visto all’evento Build 2022 il bellissimo intevento di Steve Sanderson su alcuni scenari futuribili di WebAssembly.

Come sapete sono molto appassionato di Blazor, e una delle due varianti utilizza appunto queste tecnologia.

Ma andiamo con ordine: occorre fare un piccolo recap delle puntate precedenti….

Differenze tra formato binario, linguaggi interpretati e bytecode

Mi scuserete questa introduzione forse troppo semplicistica, ma penso che si interessante capire dove si posizioni WebAssembly (=WASM).

Ci sono programmi che vengono eseguiti soltanto con l’ausilio, o l’assistenza, di un Sistema Operativo.

Per esempio C, C++, una volta compilati generano un file binario eseguibile direttamente sul sistema operativo che li ospita: per tale motivo la compilazione deve essere adatta al sistema operativo su cui si vuole mettere in esecuzione (un eseguibile fatto per Windows non potrà mai essere mandato in esecuzione sul Mac, per quanto di si impegni..).

Esistono, invece, altri tipi tipi di programmi, che sono scritti con linguaggi di scripting: in questo caso codice viene letto, interpretato ed eseguito in successione.

In altri termini per questi linguaggi non occorre una preventiva compilazione, ma il listato può essere mandato in esecuzione direttamente (ovviamente in ambiti compatibili).

L’esempio più noto è javascript che viene eseguito all’interno di un browser.

Ovviamente lavorare con questa tipologia di linguaggi è molto più semplice: una volta scritti possono essere eseguiti su qualunque piattaforma (basta appunto sia compatibile), ma esistono alcuni drawback.

Il primo è la velocità di esecuzione, inferiore rispetto ai linguaggio complilati.

Sulle macchine moderne questo spesso non un problema, ma ritengo sia utile evidenzialo.

Il secondo è che il codice è “in chiaro”, e pertanto logiche funzionali complesse sono leggibili e consultabili da chiunque.

Anche questo, comunque per molti ambiti di utilizzo, questo non rappresenta un problema.

Infine, esiste una categoria intermedia di programmi compilati in un formato intermedio, un bytecode, che per essere eseguiti richiedono la presenza di un runtime.

In questo caso gli esempi più conosciuti sono C#/.Net, che viene eseguito dal Common Language Runtime, nonchè Java, che invece usa la Java Virtual Machine.

WebAssembly è un formato bytecode che quindi può essere eseguito da qualsiasi runtime compatibile: in questo caso il runtime prende anche il nome di host.

Però WASM dispone di alcune caratteristiche interessanti: infatti può essere eseguito all’interno di un browser.

Oss.: Occorre specificare che oramai tutti i browser recenti hanno questo runtime incorporato.

L’idea originale era quella di sostituire o affiancare javascript per eseguire logiche funzionali al suo interno.

Questo per sorpassare i “difetti” di cui dispone javascript: inoltre, proprio come per il mondo .Net, l’altra cosa stuzzicante era che il codice potesse essere scritto in C#, C++, o anche altri libguaggi, smarcamdosi quindi di fatto da Javascript.

L’importante alla fine era ottenere un file bytecode formato webassembly.

Questo sorpasso WASM su Javascript alla fine non c’è mai stato, e probabilmente mai ci sarà, per tutta una serie di ragioni.

Ma è rimasto il fatto di poter mandare in esecuzione all’interno del browser del bytecode scritto con un linguaggio diverso da Javascript.

Occorre notare che ad oggi, e chissà cosa succederà in futuro, il bytecode in esecuzione all’interno del browser NON può in alcun modo intergire con la DOM della pagina visualizzata: quindi oggi in pratica WASM viene eseguito in memoria (dentro una sandbox), e per poter interagire con l’esterno (per esempio per fare chiamate http, o modificare la DOM di quanto visualizzati) utilizza (pensate un pò..) Javascript.

Questo anche per questioni di sicurezza: l’esecuzione è in una sandbox che impedisce a codice malevolo da fare cose non previste.

Quindi è possibile dire che Javascript da direttore d’orchestra con WASM si trasforma in… un suonatore di piattini….

A questo proposito esiste un concetto di import/export function: cioè di funzioni che chi mette in esecuzione il webassembly (l’host) può fornire affinchè siano richiamate appunto da webassembly, e funzioni che webassebly mette a disposizione da chi lo sta eseguendo per fare chiamate a codice appunto dentro webassembly.

Blazor WebAssembly

Come sapete Blazor WASM usa appunto WebAssembly.

Pertanto il funzionamento attuale è che l’elaborazione dei cambiamenti di stato della pagina avvenga in memoria usando WASM e all’interno della sandbox, ma i cambiamenti alla pagina stessa avvengano usando Javascript.

I vantaggi di una soluzione di questo genere è che le elaborazioni , basandosi su bytecode invece che in Javascript.

La mia affermazione precedente abbisogna di essere raffinata un poco, perchè se, sotto il punto di vista teorico questo è quello che avviene, in pratica le cose si svolgono in modo differente.

Quando si manda in esecuzione un progetto Blazor WASM il browser che si connette scarica in realtà le dll con bytecode formato .Net, nonchè un runtime .Net, che è in grado di mandarle in esecuzione.

E’ solo ed esclusivamente questo runtime che è l’unico codice WebAssembly in esecuzione.

In altri termini quello che gira dentro il browser è il runtime .Net compilato in WASM, che a sua volta è in grado di eseguire il bytecode .Net degli assembly (volgarmente: le dll del nostro progetto).

Oss.: Ecco perchè un progetto Blazor WASM quando parte scarica diversi MB: oltre al grosso file del runtime WASM, deve scaricare tutte le dll che comongono il progetto nonchè le sue dipendenze, oltre che una lunga serie di file javascript a supporto, senza contare html, immagini, css, etc etc.

Con la versione 6 di .Net Core si è ottenuta la possibilità di compilare direttamente il progetto .Net in WASM (caratteristica chiamata AOT Compilation), ma anche in questo caso le cose stanno in modo leggermente differente..

Attenzione: La AOT è una possibilità che ci è data dall’SDK ma deve essere configurata nel progetto ponendo un flag apposito all’interno della definizione del progetto.

In altri termini NON è nel default del progetto: occorre configurarlo esplicitamente (occorre impostare il flag RunAOTCompilation a true).

In presenza di AOT il codice scritto in C# viene compilato in WASM, ma purtroppo ad oggi le dll del progetto del progetto vengono sempre scaricate le dll come prima.

Questo perché per alcune parti di codice non è possibile tradurre direttamente il codice C# in WASM.

Pertanto quando vengono incontrare queste parti viene mandato in esecuzione il tutto alla vecchia maniera (runtime WebAssembly per .Net ed esecuzione delle dll del progetto .Net).

Un esempio su tutti: codice che usa reflection.

Per quanto sopra ad oggi lo “scaricato” di un progetto Blazor WASM con AOT è addirittura maggiore rispetto al solo Blazor WASM SENZA AOT.

Quindi è possibile affermare che alla data attuale il rapporto che intercorre tra Blazor e WebAssembly è…… buono, ma… non perfetto……

Sembra che la versione 7 di .Net Core sorpasserà questa soluzione mista forse proprio tramite l’adozione totale o parziale di WASI, di cui parleremo a breve.

Signore e Signori: WASI, per gli amici WebAssembly System Interface

Sin qui abbiamo parlato di WASM che viene posto in esecuzione all’interno del browser, e si appoggia su javascript per interagire con l’esterno.

Ma il fatto di avere un bytecode WASM che gira anche fuori dal browser (così come fa .Net) ha iniziato da tempo a farsi strada, ed è nato, appunto, WASI.

WASI in pratica permette al nostra vecchio amico WebAssemlby di essere mandato in esecuzione al di fuori del browser.

In pratica crea uno strato fra il file binario WebAssembly ed il sistema operativo: il suo nome lo abbiamo già incontrato, ed è host.

In pratica in questo modo WASM è in grado di parlare con il sistema operativo: accedere al file system, alle connessioni di rete e alla lettura delle variabili d’ambiente.

In questo caso grazie a WASI WebAssembly è in grado di interagire direttamente, senza l’ausilio (come nel browser) di Javascript.

WASM quando è in esecuzione all’interno del browser viene mantenuto all’interno di una sandbox, per assicurare che codice malevolo non possa “fare danni”: per proseguire questa sicurezza intrinseca nell’suo di WASM anche WASI ha scelto un approccio alla sicurezza molto stringente.

In pratica WASI è strutturato in modo modulare, in modo tale che ogni modulo si occupi di una possibile interazione del codice in esecuzione con il sistema operativo.

Per esempio esiste un modulo WASI per interagire con il filesystem per le connessioni di rete socket, etc etc.

In questo modo è possibile gestire meglio e in modo più particolareggiato la sicurezza: per bloccare l’interazione con il file system, per esempio, in fase di configurazione basta bloccare il modulo delegato a questa operazione.

E’ anche possibile configurare la quota di CPU e RAM utilizzate.

In altri termini WASI mette a disposizione tutta una serie di funzioni (import/export function) che permettono a WASM di interagire con il sistema operativo, e ognua di queste legate a un distinto modulo di WASI, che è possibile eventualmente disabilitare.

La caratteristica principale, per quanto detto, è il fatto che il codice che fa eseguire WebAssembly è in una sandbox, per cui viene eseguito in modo molto sicuro.

L’intento è quello di fornire un sistema molto leggero per eseguire del codice che interagisce con il sistema operativo con un set di funzioni predefinito e configurabile.

Ad oggi WASI è work in progress, non si può dire quale sarà il suo futuro e se ne avrà

WASI: una soluzione in cerca di un problema ?
Quindi quale potrebbe essere il futuro delle WASI-Sandbox ??

Due sole idee, che potrebbero cambiare il mondo dello sviluppo: Cloud Server (WEB API/REST e dintorni), o anche un plugin per un’applicazione (un’office plugin per esempio).

I vantaggi che si potrebbero ottenere da questa tecnologia sono i seguenti.

  1. Il bytecode è unico per tutte le piattaforme e quindi è portabile su ogni sistema operativo (compreso il mobile) e ogni CPU.
  2. E’ possibile usare un set di linguaggi differente: basta che alla fine si ottenga WASM
  3. Sicurezza intrinseca: come detto la struttura modulare assicura una imbattibile contro l’esecuzione di codice malevolo.
  4. Velocità di esecuzione molto vicina a quella nativa.

E .Net ?
Come visto Blazor WASM lavora in modo particolare: non usa direttamente WASM bensì il runtime dotnet.wasm di .Net.

Questa modalità però di funzionamento non è compatibile con WASI: inoltre la struttura usata da Blazor WASM è fatta per interagire con Javascript.

Ecco che quindi per usare WASI nel mondo .Net c’è bisogno di un compilatore differente da quello adottato per Blazor WASM: per questo è nato wasi-sdk for .Net Core (vedere linkografia).

In pratica installando il pacchetto nuget Wasi.Sdk il codice del progetto .Net Core viene compilato in WASM (non c’è bisogno di alcuna ulteriore configurazione: bsta installare il pacchetto nuget).

Oss.: La procedura di compilazione in presenza di Wasi.Sdk crea un file con estensione wasm, che è appunto il compilato WebAssembly del nostro progetto, ma mantiene anche le dll originali. Che sia chiaro: di queste ultime una volta completata la compilazione potete non farvee nulla e le potete proprio cancellare !

Oss.: Non si creda che wasi-sdk for .Net Core permetta di compilare semplici progetti console: se guardate sui samples del repo GitHb vedrete esempi che includono WebApi, SignalR, e altre cosette….

Una volta ottenuto il bytecode WASM però occorre mandarlo in esecuzione: occorre un host WASI.

Per windows per esempio wasmtime che rappresenta un primo host appunto per windows (vedere linkografia).

Inutile che Vi segni le linee di comando da usare: il tutto è work-in-progress, e inoltre la documentazione a corredo direi che è più che esplicativa e completa.

Considerazioni finali
Quanto visto è interessante, ma la cosa che ritengo più notevole è che apre le porte a nuove architetture funzionali.

Per esempio: pensate ad architetture che lavorano in modo simile a Kubernetes solo basate su host WASI.

Infatti da quello che leggo è proprio in questa direzione che si stanno muovendo gli sviluppi di WASI.

In Azure è presente già un servizio di questo genere in preview che fornisce dei servizi simili a Kubernetes con host WASI (vedere linkografia).

Detta brutalmente, e sicuramente in modo impreciso, il servizio al posto di mandare in esecuzione container manda in esecuzione codice WASM eseguito all’interno di host.

Cosa sarà di WASI nel futuro ? Una soluzione in cerca di un problema, oppure sarà una tencologia che sarà adottata estensivamente ?

Ad oggi nessuno con franchezza lo può sapere.

Spero che questi miei sproloqui siano stati di interesse e grazie per avermi letto.

Likografia
YouTube – Future Possibilities for .NET Core and WASI (WebAssembly on the Server) | OD108
Blazor Dev Italia – Che cos’è, veramente, WebAssembly
GitHub: Experimental WASI SDK for .NET Core
GitHub: Wasmtime
M$: Create WebAssembly System Interface (WASI) node pools in Azure Kubernetes Service (AKS) to run your WebAssembly (WASM) workload (preview)