Threads WebAssembly prêts à être essayés dans Chrome 70

La prise en charge des threads WebAssembly est disponible dans Chrome 70 dans le cadre d'une phase d'évaluation.

Alex Danilo

WebAssembly (Wasm) permet de compiler du code écrit en C++ et dans d'autres à utiliser sur le Web. Une fonctionnalité très utile des applications natives est la possibilité d'utiliser des threads, une primitive pour le calcul parallèle. Most C et les développeurs C++ connaissent pthreads, qui est une API standardisée pour gérer les threads d'une application.

Le groupe de la communauté WebAssembly s'est efforcé d'intégrer des threads sur le Web pour permettre de véritables applications multithreads. Dans le cadre de cet effort, V8 a implémenté la prise en charge nécessaire des threads dans le moteur WebAssembly, disponible via un essai Origin. Phases d'évaluation permettent aux développeurs de tester de nouvelles fonctionnalités Web avant qu'elles ne soient standardisés. Cela nous permet de recueillir des commentaires concrets de développeurs intrépides, ce qui est essentiel pour valider et améliorer les nouvelles fonctionnalités.

La version de Chrome 70 est compatible avec les threads pour WebAssembly. les développeurs intéressés de commencer à les utiliser et de nous faire part de leurs commentaires.

Des fils de discussion ? Qu'en est-il des nœuds de calcul ?

Les navigateurs sont compatibles avec le parallélisme via les Web Workers depuis 2012 dans Chrome 4. En fait, il est normal d'entendre des termes tels que "sur le thread principal", etc. Cependant, les Web Workers ne partagent pas de données modifiables entre eux, mais s'appuient sur la transmission de messages pour la communication. En fait, Chrome alloue un nouveau moteur V8 pour chacun d'eux (appelés "isolates"). Isoler ne partage ni code compilé, ni des objets JavaScript et ne peuvent donc pas partager de données modifiables telles que les pthreads.

En revanche, les threads WebAssembly peuvent partager la même mémoire Wasm. Le stockage sous-jacent de la mémoire partagée est effectué avec un SharedArrayBuffer, une primitive JavaScript qui permet de partager simultanément le contenu d'un seul ArrayBuffer entre les nœuds de calcul. Chaque thread WebAssembly s'exécute dans un nœud de travail Web, mais leur mémoire Wasm partagée leur permet de fonctionner comme sur les plates-formes natives. Cela signifie que les applications qui utilisent des threads Wasm responsable de la gestion de l'accès à la mémoire partagée, comme dans tout à une application avec fils de discussion. Il existe de nombreuses bibliothèques de code écrites en C ou C++ qui utilisent des pthreads, qui peuvent être compilés dans Wasm et exécutés avec en mode thread, ce qui permet à davantage de cœurs de travailler simultanément sur les mêmes données.

Exemple simple

Voici un exemple de programme C simple qui utilise des threads.

#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;
}

Ce code commence par la fonction main(), qui déclare deux variables fg_val et bg_val. Il existe également une fonction appelée fibonacci(), qui sera appelée par les deux threads de cet exemple. La fonction main() crée un thread d'arrière-plan à l'aide de pthread_create(), dont la tâche consiste à calculer la valeur de la séquence de nombres de Fibonacci correspondant à la valeur de la variable bg_val. Pendant ce temps, Fonction main() exécutée dans le thread de premier plan la calcule pour la variable fg_val. Une fois l'exécution du thread en arrière-plan terminée, les résultats sont imprimés.

Compiler pour la compatibilité avec les threads

Tout d'abord, vous devez disposer du SDK Emscripten. installé, de préférence la version 1.38.11 ou ultérieure. Pour compiler notre exemple de code avec les threads activés pour l'exécution dans le navigateur, nous devons transmettre quelques options supplémentaires au compilateur emcc emscripten. Notre la ligne de commande se présente comme suit:

emcc -O2 -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=2 -o test.js test.c

L'argument de ligne de commande "-s USE_PTHREADS=1" active la prise en charge des threads pour le module WebAssembly compilé et l'argument "-s PTHREAD_POOL_SIZE=2" ; indique au compilateur de générer un pool de deux (2) threads.

Lorsque le programme est exécuté, il charge le module WebAssembly, crée un Web Worker pour chacun des threads du pool de threads, partage le module avec chacun des workers (dans ce cas, il y en a deux), et ceux-ci sont utilisés chaque fois qu'un appel à pthread_create() est effectué. Chaque nœud de calcul instancie le module Wasm avec la même mémoire, ce qui leur permet de coopérer. Les dernières modifications de V8 dans la version 7.0 partagent le code natif compilé des modules Wasm transmis entre les nœuds de calcul, ce qui permet même aux applications très volumineuses de s'adapter à de nombreux nœuds de calcul. Notez qu'il est judicieux de vous assurer que la taille du pool de threads est égale au nombre maximal de threads dont votre application a besoin, sinon la création de threads risque d'échouer. En même temps, si la taille du pool de threads est trop importante, vous créerez des Web Workers inutiles qui ne feront rien d'autre que d'utiliser de la mémoire.

Comment tester cette fonctionnalité ?

Le moyen le plus rapide de tester notre module WebAssembly consiste à activer la compatibilité expérimentale avec les threads WebAssembly à partir de Chrome 70. Accédez à l'URL about://flags dans votre navigateur, comme indiqué ci-dessous :

Page des indicateurs Chrome

Recherchez ensuite le paramètre expérimental des threads WebAssembly qui se présente comme suit:

Paramètre des threads WebAssembly

Définissez le paramètre sur Enabled (Activé), comme indiqué ci-dessous, puis redémarrez votre navigateur.

Paramètre des threads WebAssembly activé

Une fois le navigateur redémarré, nous pouvons essayer de charger le module WebAssembly avec une page HTML minimale, qui ne contient que ce contenu :

<!DOCTYPE html>
<html>
  <title>Threads test</title>
  <body>
    <script src="test.js"></script>
  </body>
</html>

Pour essayer cette page, vous devez exécuter un type de serveur Web et le charger depuis votre navigateur. Le module WebAssembly sera alors chargé et exécuté. Ouverture Les outils de développement nous montrent le résultat de l'exécution. Vous devriez obtenir un résultat semblable au l'image de sortie ci-dessous dans la console:

Sortie de la console du programme fibonacci

Notre programme WebAssembly avec des threads a bien été exécuté. Nous vous conseillons de tester votre propre application en fils de discussion en suivant les étapes décrites ci-dessus.

Effectuer des tests sur le terrain avec une phase d'évaluation

L'activation des indicateurs expérimentaux dans le navigateur permet d'essayer des threads. développement d'applications, mais si vous souhaitez tester votre application vous pouvez utiliser ce que l'on appelle Phase d'évaluation.

Les phases d'évaluation vous permettent de tester des fonctionnalités expérimentales avec vos utilisateurs en obtenant un jeton de test associé à votre domaine. Vous pouvez ensuite déployer votre application attendez-vous à ce qu'elle fonctionne dans un navigateur compatible avec la fonctionnalité que vous testez (dans dans ce cas, Chrome 70 et versions ultérieures). Pour obtenir votre propre jeton afin d'exécuter un test d'origine, remplissez ce formulaire.

Nous avons hébergé notre exemple simple ci-dessus à l'aide d'un jeton d'essai d'origine afin que vous puissiez l'essayer par vous-même sans avoir à créer quoi que ce soit.

Si vous souhaitez voir ce que quatre threads exécutés en parallèle peuvent faire pour l'art ASCII, vous devez également regarder cette démonstration.

Envoyez-nous vos commentaires.

Les threads WebAssembly sont une nouvelle primitive extrêmement utile pour le portage d'applications sur le Web. Il est désormais possible d'exécuter des applications et des bibliothèques C et C++ qui nécessitent la compatibilité avec pthreads dans l'environnement WebAssembly.

Nous aimerions connaître l'avis des développeurs qui testent cette fonctionnalité, car elle nous aidera éclairer le processus de normalisation et valider son utilité. Le meilleur moyen d'envoyer des commentaires est de signaler des problèmes et/ou impliqués dans la standardisation au cours du processus Groupe de la communauté WebAssembly.