Come abbiamo utilizzato WebAssembly per velocizzare un'applicazione web 20 volte

Come abbiamo utilizzato WebAssembly per velocizzare un'applicazione web 20 volte

In questo articolo viene illustrato un caso per velocizzare un'applicazione browser sostituendo i calcoli JavaScript con WebAssembly.

WebAssembly: che cos'è?

In breve, questo è un formato di istruzioni binario per una macchina virtuale basata su stack. Wasm (nome abbreviato) è spesso chiamato linguaggio di programmazione, ma non lo è. Il formato dell'istruzione viene eseguito nel browser insieme a JavaScript.

È importante che WebAssembly possa essere ottenuto compilando sorgenti in linguaggi come C/C++, Rust, Go. Qui vengono utilizzati la tipizzazione statistica e il cosiddetto modello di memoria piatta. Il codice, come accennato in precedenza, è archiviato in un formato binario compatto, rendendolo veloce quasi quanto l'esecuzione dell'applicazione tramite la riga di comando. Queste funzionalità hanno portato alla crescita della popolarità di WebAssembly.

Ti ricordiamo: per tutti i lettori di "Habr" - uno sconto di 10 rubli al momento dell'iscrizione a qualsiasi corso Skillbox utilizzando il codice promozionale "Habr".

Skillbox consiglia: Corso pratico "Sviluppatore mobile PRO".

Attualmente, Wasm è utilizzato in molte applicazioni, da giochi come Doom 3 ad applicazioni web-ported come Autocad e Figma. Wasm viene utilizzato anche in aree come il serverless computing.

Questo articolo fornisce un esempio di utilizzo di Wasm per velocizzare un servizio Web di analisi. Per chiarezza, abbiamo preso un'applicazione funzionante scritta in C, che è compilata in WebAssembly. Il risultato verrà utilizzato per sostituire le sezioni con prestazioni inferiori di JS.

Trasformazione dell'applicazione

L'esempio utilizzerà il servizio browser fastq.bio, destinato ai genetisti. Lo strumento consente di valutare la qualità del sequenziamento del DNA (decifrazione).

Ecco un esempio dell'applicazione in azione:

Come abbiamo utilizzato WebAssembly per velocizzare un'applicazione web 20 volte

Non vale la pena entrare nei dettagli del processo in quanto sono piuttosto complessi per i non specialisti, ma in breve gli scienziati possono utilizzare l’infografica sopra per capire se il processo di sequenziamento del DNA è andato liscio e quali problemi sono sorti.

Questo servizio ha alternative, programmi desktop. Ma fastq.bio ti consente di velocizzare il tuo lavoro visualizzando i dati. Nella maggior parte degli altri casi, è necessario essere in grado di lavorare con la riga di comando, ma non tutti i genetisti hanno l'esperienza necessaria.

Tutto funziona semplicemente. L'input sono dati presentati sotto forma di file di testo. Questo file è generato da strumenti di sequenziamento specializzati. Il file contiene un elenco di sequenze di DNA e un punteggio di qualità per ciascun nucleotide. Il formato del file è .fastq, motivo per cui il servizio ha preso il nome.

Implementazione in JavaScript

Il primo passo dell'utente quando lavora con fastq.bio è selezionare il file appropriato. Utilizzando l'oggetto File, l'applicazione legge un campione casuale di dati da un file ed elabora quel batch. Il compito di JavaScript qui è eseguire semplici operazioni sulle stringhe e calcolare le metriche. Uno di questi è il numero di nucleotidi A, C, G e T su diversi frammenti di DNA.

Dopo aver calcolato gli indicatori necessari, questi vengono visualizzati utilizzando Plotly.js e il servizio inizia a funzionare con un nuovo campione di dati. Il suddivisione viene eseguito per migliorare la qualità della UX. Se lavori con tutti i dati contemporaneamente, il processo si bloccherà per un po' di tempo, poiché i file con i risultati della sequenza occupano centinaia di gigabyte di spazio file. Il servizio prende dati di dimensioni variabili da 0,5 a 1 MB e lavora con essi passo dopo passo, costruendo dati grafici.

Ecco come funziona:

Come abbiamo utilizzato WebAssembly per velocizzare un'applicazione web 20 volte

Il rettangolo rosso contiene l'algoritmo di trasformazione delle stringhe per ottenere la visualizzazione. Questa è la parte più impegnativa dal punto di vista computazionale del servizio. Vale la pena provare a sostituirlo con Wasm.

Test di WebAssembly

Per valutare la possibilità di utilizzare Wasm, il team del progetto ha iniziato a cercare soluzioni già pronte per la creazione di metriche QC (QC - controllo qualità) basate su file fastq. La ricerca è stata effettuata tra strumenti scritti in C, C++ o Rust, in modo che fosse possibile portare il codice su WebAssembly. Inoltre, lo strumento non doveva essere “grezzo”; era necessario un servizio già testato dagli scienziati.

Di conseguenza, la scelta è stata fatta a favore di seq. L'applicazione è abbastanza popolare, è open source, la lingua sorgente è C.

Prima di passare a Wasm, vale la pena considerare il principio di compilazione di seqtk per desktop. Secondo il Makefile, ecco cosa ti serve:

# Compile to binary
$ gcc seqtk.c 
   -o seqtk 
   -O2 
   -lm 
   -lz

In linea di principio puoi compilare seqtk usando Emscripten. Se non c'è, ci arrangiamo. Immagine Docker.

$ docker pull robertaboukhalil/emsdk:1.38.26
$ docker run -dt --name wasm-seqtk robertaboukhalil/emsdk:1.38.26

Se lo si desidera, Puoi assemblarlo da solo, ma ci vuole tempo.

All'interno di un contenitore, puoi facilmente utilizzare emcc come alternativa a gcc:

# Compile to WebAssembly
$ emcc seqtk.c 
    -o seqtk.js 
    -O2 
    -lm 
    -s USE_ZLIB=1 
    -s FORCE_FILESYSTEM=1

Modifiche minime:

Invece di eseguire l'output in un file binario, Emscripten utilizza .wasm e .js per generare i file, che vengono utilizzati per eseguire il modulo WebAssemby.

Il flag USE_ZLIB viene utilizzato per supportare la libreria zlib. La libreria è stata distribuita e portata su WebAssembly ed Emscripten la include nel progetto.

Il file system virtuale Emscriptpten è attivato. Questo FS simile a POSIX, in esecuzione nella RAM all'interno del browser. Quando la pagina viene aggiornata, la memoria viene cancellata.

Per capire perché è necessario un file system virtuale, vale la pena confrontare il modo in cui esegui seqtk dalla riga di comando con il modo in cui esegui un modulo WebAssembly compilato.

# On the command line
$ ./seqtk fqchk data.fastq
 
# In the browser console
> Module.callMain(["fqchk", "data.fastq"])

È necessario ottenere l'accesso al file system virtuale per non riscrivere seqtk per la stringa anziché per l'input del file. In questo caso, il frammento di dati viene visualizzato come file data.fastq nel FS virtuale con una chiamata a main() seqtk su di esso.

Ecco la nuova architettura:

Come abbiamo utilizzato WebAssembly per velocizzare un'applicazione web 20 volte

La figura mostra che invece dei calcoli nel thread principale del browser, WebWorker. Questo metodo consente di eseguire calcoli in un thread in background senza influire sulla reattività del browser. Ebbene, il controller WebWorker avvia il Worker, gestendo la sua interazione con il thread principale.

Il comando seqtk viene eseguito utilizzando Worker sul file montato. Dopo il completamento dell'esecuzione, il Lavoratore produce un risultato sotto forma di Promessa. Quando un messaggio viene ricevuto dal thread principale, il risultato viene utilizzato per aggiornare i grafici. E così via in diverse iterazioni.

Che dire delle prestazioni di WebAssembly?

Per valutare il cambiamento nelle prestazioni, il team del progetto ha utilizzato il parametro delle operazioni di lettura al secondo. Il tempo necessario per creare grafici interattivi non viene preso in considerazione poiché entrambe le implementazioni utilizzano JavaScript.

Utilizzando la soluzione pronta all'uso, l'aumento delle prestazioni è stato di nove volte.

Come abbiamo utilizzato WebAssembly per velocizzare un'applicazione web 20 volte

Questo è un risultato eccellente, ma, a quanto pare, c'è anche l'opportunità di ottimizzarlo. Il fatto è che un gran numero di risultati dell'analisi QC non vengono utilizzati da seqtk, quindi possono essere eliminati. Se si esegue questa operazione, il risultato migliora di 13 volte rispetto a JS.

Come abbiamo utilizzato WebAssembly per velocizzare un'applicazione web 20 volte

È stato ottenuto semplicemente commentando i comandi printf().

Ma non è tutto. Il fatto è che in questa fase fastq.bio riceve i risultati dell'analisi chiamando diverse funzioni C. Ciascuna di esse calcola il proprio insieme di caratteristiche, in modo che ogni frammento del file venga letto due volte.

Per aggirare questo problema, si è deciso di combinare due funzioni in una. Di conseguenza, la produttività è aumentata di 20 volte.

Come abbiamo utilizzato WebAssembly per velocizzare un'applicazione web 20 volte

Vale la pena notare che non sempre è possibile ottenere un risultato così eccezionale. In alcuni casi, le prestazioni diminuiranno, quindi vale la pena valutare ogni caso.

In conclusione, possiamo dire che Wasm offre un'opportunità per migliorare le prestazioni dell'applicazione, ma è necessario utilizzarlo con saggezza.

Skillbox consiglia:

Fonte: habr.com

Aggiungi un commento