Il supporto dei thread WebAssembly è stato implementato in Chrome 70 nell'ambito di una prova di origine.
WebAssembly (Wasm) consente di compilare il codice scritto in C++ e in altri linguaggi per l'esecuzione sul web. Una funzionalità molto utile delle applicazioni native è la possibilità di utilizzare i thread, un elemento di base per i calcoli paralleli. La maggior parte degli sviluppatori C e C++ conosce pthreads, un'API standardizzata per la gestione dei thread in un'applicazione.
Il gruppo della community WebAssembly si sta adoperando per portare i thread sul web in modo da consentire applicazioni multithread reali. Nell'ambito di questo impegno, V8 ha implementato il supporto necessario per i thread nel motore WebAssembly, disponibile tramite una prova Origin. Le prove di origine consentono agli sviluppatori di sperimentare nuove funzionalità web prima che vengano completamente standardizzate. In questo modo possiamo raccogliere feedback reali da sviluppatori intrepidi, che sono fondamentali per convalidare e migliorare le nuove funzionalità.
La release di Chrome 70 supporta i thread per WebAssembly e invitiamo gli sviluppatori interessati a iniziare a utilizzarli e a inviarci un feedback.
Thread? Che ne dici di Workers?
I browser supportano il parallelismo tramite Web Worker dal 2012 in Chrome 4. Infatti, è normale sentire termini come "nel thread principale" e così via. Tuttavia, i Web Worker non condividono dati mutabili tra loro, ma si basano sulla trasmissione di messaggi per la comunicazione. In effetti, Chrome alloca un nuovo motore V8 per ciascuno di questi (chiamati istanze). Gli istanze isolate non condividono né il codice compilato né gli oggetti JavaScript e, di conseguenza, non possono condividere dati mutabili come i pthread.
I thread WebAssembly, invece, sono thread che possono condividere la stessa memoria Wasm. Lo spazio di archiviazione sottostante della memoria condivisa viene realizzato con un SharedArrayBuffer, una primitiva JavaScript che consente di condividere i contenuti di un singolo ArrayBuffer contemporaneamente tra i worker. Ogni thread WebAssembly viene eseguito in un worker web, ma la memoria Wasm condivisa consente loro di funzionare in modo molto simile alle piattaforme native. Ciò significa che le applicazioni che utilizzano i thread Wasm sono responsabili della gestione dell'accesso alla memoria condivisa come in qualsiasi applicazione con threading tradizionale. Esistono molte librerie di codice scritte in C o C++ che utilizzano pthreads e che possono essere compilate in Wasm ed eseguite in modalità con threading effettivo, consentendo a più core di lavorare contemporaneamente sugli stessi dati.
Un esempio semplice
Ecco un esempio di un semplice programma in C che utilizza i thread.
#include <pthread.h>
#include <stdio.h>
// Calculate Fibonacci numbers shared function
int fibonacci(int iterations) {
int val = 1;
int last = 0;
if (iterations == 0) {
return 0;
}
for (int i = 1; i < iterations; i++) {
int seq;
seq = val + last;
last = val;
val = seq;
}
return val;
}
// Start function for the background thread
void *bg_func(void *arg) {
int *iter = (void *)arg;
*iter = fibonacci(*iter);
return arg;
}
// Foreground thread and main entry point
int main(int argc, char *argv[]) {
int fg_val = 54;
int bg_val = 42;
pthread_t bg_thread;
// Create the background thread
if (pthread_create(&bg_thread, NULL, bg_func, &bg_val)) {
perror("Thread create failed");
return 1;
}
// Calculate on the foreground thread
fg_val = fibonacci(fg_val);
// Wait for background thread to finish
if (pthread_join(bg_thread, NULL)) {
perror("Thread join failed");
return 2;
}
// Show the result from background and foreground threads
printf("Fib(42) is %d, Fib(6 * 9) is %d\n", bg_val, fg_val);
return 0;
}
Il codice inizia con la funzione main()
che dichiara due variabili fg_val
e bg_val
. Esiste anche una funzione chiamata
fibonacci()
, che verrà chiamata da entrambi i
thread in questo esempio. La funzione main()
crea un thread in background utilizzando pthread_create()
il cui compito è calcolare il valore della sequenza di numeri di Fibonacci corrispondente al
valore della variabile bg_val
. Nel frattempo, la funzione
main()
in esecuzione nel thread in primo piano
lo calcola per la variabile fg_val
. Una volta completata l'esecuzione del thread in background, i risultati vengono stampati.
Compilare per il supporto di Thread
Innanzitutto, devi avere installato l'SDK emscripten, preferibilmente la versione 1.38.11 o successiva. Per compilare il codice di esempio con thread abilitati per l'esecuzione nel browser, dobbiamo passare un paio di flag aggiuntivi al compilatore emscripten emcc. La nostra riga di comando è la seguente:
emcc -O2 -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=2 -o test.js test.c
L'argomento della riga di comando "-s USE_PTHREADS=1
" attiva il supporto dei thread per il modulo WebAssembly compilato e l'argomento "-s PTHREAD_POOL_SIZE=2
" indica al compilatore di generare un pool di due (2) thread.
Quando il programma viene eseguito, sotto il cofano carica il modulo WebAssembly,
crea un web worker per ogni thread nel pool di thread, condivide il modulo
con ciascuno dei worker, in questo caso sono 2, che verranno utilizzati ogni volta che viene eseguita una
chiamata a pthread_create()
. Ogni worker esegue l'inizializzazione del modulo Wasm con la stessa memoria, il che consente loro di collaborare. Le modifiche più recenti di V8 nella versione 7.0 condividono il codice nativo compilato dei moduli Wasm che vengono trasmessi tra i worker, il che consente anche ad applicazioni molto grandi di scalare su molti worker. Tieni presente che è opportuno assicurarsi che le dimensioni del pool di thread siano uguali al
numero massimo di thread di cui ha bisogno l'applicazione, altrimenti la creazione dei thread potrebbe non riuscire.
Allo stesso tempo, se le dimensioni del pool di thread sono troppo grandi, creerai worker web non necessari che rimarranno inutilizzati occupando memoria.
Come provarlo
Il modo più rapido per testare il nostro modulo WebAssembly è attivare il supporto sperimentale dei thread WebAssembly in Chrome 70 e versioni successive. Vai all'URL about://flags
nel browser come mostrato di seguito:
Poi, individua l'impostazione dei thread WebAssembly sperimentali, che ha il seguente aspetto:
Imposta l'opzione su Abilitato come mostrato di seguito, quindi riavvia il browser.
Dopo il riavvio del browser, possiamo provare a caricare il modulo WebAssembly threaded con una pagina HTML minima contenente solo questi contenuti:
<!DOCTYPE html>
<html>
<title>Threads test</title>
<body>
<script src="test.js"></script>
</body>
</html>
Per provare questa pagina, devi eseguire una qualche forma di server web e caricarla dal browser. Il modulo WebAssembly verrà caricato ed eseguito. L'apertura di DevTools mostra l'output dell'esecuzione e nella console dovresti vedere qualcosa di simile all'immagine di output riportata di seguito:
Il nostro programma WebAssembly con thread è stato eseguito correttamente. Ti invitiamo a provare la tua applicazione con thread seguendo i passaggi descritti sopra.
Test sul campo con una prova dell'origine
Provare i thread attivando i flag sperimentali nel browser è utile ai fini dello sviluppo, ma se vuoi testare la tua applicazione sul campo, puoi farlo con la cosiddetta prova dell'origine.
Le prove dell'origine ti consentono di provare le funzionalità sperimentali con i tuoi utenti ottenendo un token di test associato al tuo dominio. Puoi quindi eseguire il deployment dell'app e prevedere che funzioni in un browser in grado di supportare la funzionalità che stai testando (in questo caso Chrome 70 e versioni successive). Per ottenere il tuo token per eseguire una prova dell'origine, utilizza il modulo di richiesta.
Abbiamo ospitato il nostro semplice esempio qui sopra utilizzando un token di prova dell'origine, quindi puoi provarlo tu stesso senza dover creare nulla.
Se vuoi scoprire cosa possono fare 4 thread in esecuzione in parallelo per l'ASCII art, dai un'occhiata anche a questa demo.
Inviaci i tuoi commenti
I thread WebAssembly sono un nuovo elemento estremamente utile per il porting delle applicazioni sul web. Ora è possibile eseguire applicazioni e librerie C e C++ che richiedono il supporto di pthreads nell'ambiente WebAssembly.
Stiamo cercando il feedback degli sviluppatori che provano questa funzionalità, in quanto ci aiuterà a informare il processo di standardizzazione e a convalidarne l'utilità. Il modo migliore per inviare feedback è segnalare i problemi e/o partecipare al processo di standardizzazione nel gruppo della community WebAssembly.