web-dev-qa-db-fra.com

Parallélisation des tâches dans Node.js

J'ai certaines tâches que je veux faire dans JS qui nécessitent beaucoup de ressources. Pour cette question, supposons qu'il s'agit de calculs lourds, plutôt que d'accès au système. Maintenant, je veux exécuter les tâches A, B et C en même temps et exécuter une fonction D lorsque cela est fait.

La bibliothèque async fournit un échafaudage sympa pour cela:

async.parallel([A, B, C], D);

Si ce que je fais n'est que des calculs, cela fonctionnera toujours de manière synchrone (sauf si la bibliothèque place les tâches sur différents threads elle-même, ce qui, je pense, n'est pas le cas). Comment puis-je faire en sorte que cela soit réellement parallèle? Que fait généralement le code asynchrone pour ne pas bloquer l'appelant (lorsque vous travaillez avec NodeJS)? Commence-t-il un processus enfant ?

29
Jeroen De Dauw

Comment puis-je faire en sorte que cela soit réellement parallèle?

Tout d'abord, vous ne serez pas vraiment exécuté en parallèle dans une application à nœud unique. Une application de nœud s'exécute sur un seul thread et un seul événement à la fois est traité par la boucle d'événements du nœud. Même lors de l'exécution sur un boîtier multicœur, vous n'obtiendrez pas le parallélisme du traitement dans une application de nœud.

Cela dit, vous pouvez obtenir le parallélisme de traitement sur une machine multicœur en forçant le code dans des processus de nœud séparés ou en générant un processus enfant . En effet, cela vous permet de créer plusieurs instances du nœud lui-même et de communiquer avec ces processus de différentes manières (par exemple, stdout, processus fork IPC). De plus, vous pouvez choisir de séparer le fonctions (par responsabilité) dans leur propre application/serveur de nœud et l'appeler via RPC.

À quoi sert généralement le code async pour ne pas bloquer l'appelant (lorsque vous travaillez avec NodeJS)? Commence-t-il un processus enfant?

Il ne démarre pas un nouveau processus. En dessous, quand async.parallel est utilisé dans node.js , il utilise process.nextTick(). Et nextTick () vous permet d'éviter de bloquer l'appelant en reportant le travail sur une nouvelle pile afin que vous puissiez entrelacer des tâches gourmandes en CPU, etc.

Longue histoire courte

Node ne facilite pas la sortie de la boîte de dialogue multiprocesseur. Node vous propose à la place une conception non bloquante et une boucle d'événement qui exploite un thread sans partager la mémoire. Plusieurs threads ne peuvent pas partager les données/mémoire, donc les verrous ne sont pas nécessaires. Node est sans verrouillage . Un processus de nœud exploite un thread, ce qui rend le nœud à la fois sûr et puissant.

Lorsque vous devez répartir le travail entre plusieurs processus, utilisez une sorte de message qui passe pour communiquer avec les autres processus/serveurs. par ex. IPC/RPC.


Pour plus d'informations, voir:

Réponse impressionnante de SO on Qu'est-ce que Node.js ... avec des tonnes de bonté.

Comprendre process.nextTick ()

37
Matt Self

Asynchrone et parallèle ne sont pas la même chose. Asynchrone signifie que vous n'avez pas à attendre la synchronisation. Parallèle signifie que vous pouvez faire plusieurs choses en même temps. Node.js est uniquement asynchrone, mais son seul thread 1. Il ne peut fonctionner que sur 1 chose à la fois. Si vous avez un calcul de longue durée, vous devez démarrer un autre processus, puis faire en sorte que votre processus node.js attende les résultats de manière asynchrone.

Pour ce faire, vous pouvez utiliser child_process.spawn puis lire les données de stdin.

http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options

var spawn = require('child_process').spawn;
var process2 = spawn('sh', ['./computationProgram', 'parameter'] );

process2.stderr.on('data', function (data) {
    //handle error input
});

process2.stdout.on('data', function (data) {
    //handle data results
});
14
Joshua Allen

Gardez à l'esprit que les E/S sont parallélisées par Node.js; seuls vos rappels JavaScript sont monothread.

En supposant que vous écrivez un serveur, une alternative à l'ajout de la complexité des processus de génération ou de forking consiste à simplement construire des serveurs de nœuds sans état et à exécuter une instance par cœur, ou mieux encore à exécuter de nombreuses instances chacune dans leur propre micro-serveur virtualisé. Coordonnez les demandes entrantes à l'aide d'un proxy inverse ou d'un équilibreur de charge.

Vous pouvez également décharger le calcul sur un autre serveur, peut-être MongoDB (en utilisant MapReduce) ou Hadoop.

Pour être vraiment hardcore, vous pouvez écrire un plugin Node en C++ et avoir un contrôle précis de la parallélisation du code de calcul. L'accélération à partir de C++ pourrait de toute façon éliminer le besoin de parallélisation.

Vous pouvez toujours écrire du code pour effectuer des tâches à forte intensité de calcul dans une autre langue la mieux adaptée au calcul numérique, et par exemple les exposer via une API REST.

Enfin, vous pouvez peut-être exécuter le code sur le GPU en utilisant node-cuda ou quelque chose de similaire selon le type de calcul (tous ne peuvent pas être optimisés pour le GPU).

Oui, vous pouvez bifurquer et générer d'autres processus, mais il me semble que l'un des principaux avantages du nœud est de ne pas avoir à se soucier de la parallélisation et du threading, et donc de contourner une grande quantité de complexité.

4
wprl

Selon votre cas d'utilisation, vous pouvez utiliser quelque chose comme

task.js Interface simplifiée pour obtenir du code gourmand en CPU à exécuter sur tous les cœurs (node.js et web)

Un exemple serait

function blocking (exampleArgument) {
    // block thread
}

// turn blocking pure function into a worker task
const blockingAsync = task.wrap(blocking);

// run task on a autoscaling worker pool
blockingAsync('exampleArgumentValue').then(result => {
    // do something with result
});
3
Chad Scira

Tout récemment, nous avons rencontré parallel.js, mais il semble utiliser en fait plusieurs cœurs et a également des fonctionnalités de type de réduction de carte. http://adambom.github.io/parallel.js/

2
Joel