Version Node.js 10.5: multithreading prêt à l'emploi


La semaine dernière, Node.js version 10.5.0 a été publiée, contenant une innovation dont l'importance est difficile à surestimer - la prise en charge du multithreading sous la forme du module worker_threads . Immédiatement, je ferai une réservation. L'API est au stade expérimental et peut donc changer, mais maintenant vous pouvez faire une première impression et vous faire une idée des principes et technologies énoncés dans sa fondation. Et si vous en avez envie, alors participez à la finalisation de l'interface, à l'écriture de code ou à la correction de bugs (liste des problèmes ).


Histoire d'apparence


Tout au long de la vie de Node.js, la seule façon de paralléliser l'informatique était de démarrer un nouveau processus, par exemple, en utilisant le module de cluster. Pour de nombreuses raisons, cette approche ne convient pas aux développeurs, en particulier parce qu'elle conduit à une charge répétée de code exécutable Node.js avec tous les modules intégrés dans la mémoire de l'ordinateur, ce qui est un moyen inefficace de dépenser des ressources.


Néanmoins, la discussion sur l'implémentation du multithreading dans Node.js a toujours reposé sur la complexité de la V8 et un grand nombre d'inconnues: comment connecter des modules natifs, partager de la mémoire, communiquer entre des threads, etc. Et tandis que les développeurs cherchaient de quel côté aborder le sujet sur le Web, l' API Worker a été implémentée avec succès, qui est devenue une ligne directrice aux étapes initiales. Le développement a commencé avec addaleax et a été repris par la communauté.


Un travail actif a été effectué au cours de l'année, au cours duquel les exigences de conception ont été spécifiées et l'API a acquis ses propres fonctionnalités spécifiques à Node.js, et le module lui-même a été appelé worker_threads. Ci-dessous je décrirai brièvement worker_threads en termes généraux, et pour une étude détaillée, je vous conseille de visiter la page de documentation officielle.


La description


Comme mentionné ci-dessus, l'objectif de ce développement est d'améliorer la productivité en répartissant la charge sur des threads distincts au sein d'un même processus, au lieu de démarrer plusieurs processus. Par conséquent, les threads prendront en charge la connexion de tous les modules disponibles pour le processus principal (actuellement, les modules natifs ne sont pas pris en charge).


Comme dans l'API Worker, l'interaction entre le flux principal et le flux enfant est réalisée en transférant des objets transférables via postMessage, ce qui évite les problèmes d'accès simultané, bien qu'il nécessite des accès mémoire supplémentaires pour copier les données. Dans ce cas, des objets comme SharedArrayBuffer conservent leur comportement et ne provoquent pas de réallocation.


MessageChannel et MessagePort ont été extraits de WebAPI , ce qui vous permet de créer des canaux de messagerie isolés et de les transférer entre les threads.


Afin d'essayer worker_threads en action, lorsque vous démarrez le processus, vous devez spécifier un indicateur spécial:


node --experimental-worker main.js 

Exemple


Étant donné que l'API peut encore changer, je ne le décrirai pas, mais je donnerai un exemple d'échange de messages entre les threads parent et enfant, dans lequel le thread enfant signale son threadId via MessagePort et se ferme.


Flux principal


Exemple de code pour le thread principal:


 // main.js const {Worker} = require('worker_threads'); const worker = new Worker(__dirname + '/worker.js'); worker.on('online', () => { console.log('Worker ready'); }); worker.on('message', (msg) => { console.log('Worker message:', msg); }); worker.on('error', (err) => { console.error('Worker error:', err); }); worker.on('exit', (code) => { console.log('Worker exit code:', code); }); 

Flux enfant


Le thread enfant vit jusqu'à ce que sa boucle d'événements soit vide. Ainsi, immédiatement après l' worker.js du code de worker.js thread sera automatiquement fermé. Pour communiquer avec le parent, parentPort est utilisé:


 // worker.js const {threadId, parentPort} = require('worker_threads'); parentPort.postMessage(`Hello from thread #${threadId}.`); // Exit happens here 

Dans le thread enfant, l'objet de processus est remplacé et son comportement est légèrement différent du comportement de processus dans le thread parent. En particulier, il n'y a aucun moyen de répondre aux signaux SIGNINT, de modifier les valeurs de process.env et d'appeler process.exit arrêtera uniquement le travailleur, mais pas l'ensemble du processus.


Conclusion


Les travailleurs simplifieront considérablement la création d'applications qui nécessitent une interaction entre des sections de code exécutables parallèles et, ce qui est particulièrement important, rend la communication et le contrôle de flux la manière la plus évidente. Et permettra également d'éviter les restrictions spécifiques à la plate-forme causées par la différence entre Windows et Unix. Je suis sûr que les opportunités qui s'ouvriront attireront de nouveaux développeurs qui n'ont pas encore opté pour Node.js. En attendant, continuez de surveiller les modifications et connectez-vous au processus de développement d'API dans le référentiel .


Les références


Source: https://habr.com/ru/post/fr415165/


All Articles