Le nœud est conçu pour gérer efficacement les opérations d'E / S, mais vous devez savoir que certains types de programmes ne conviennent pas à ce mode. Par exemple, si vous prévoyez d'utiliser le nœud pour gérer une tâche à forte intensité de CPU, vous pouvez bloquer la boucle d'événement et ainsi réduire la réponse du programme. Une alternative consiste à attribuer des tâches à forte intensité de processeur à un processus distinct à gérer, libérant ainsi la boucle d'événement. Le nœud vous permet d'approuver un processus et d'utiliser ce nouveau processus en tant qu'enfant de son processus parent. Dans le nœud, le processus enfant peut communiquer à double sens avec le processus parent, et dans une certaine mesure, le processus parent peut également surveiller et gérer le processus de l'enfant.
Un autre cas où vous devez utiliser un processus enfant est lorsque vous souhaitez simplement exécuter une commande externe et laisser Node obtenir la valeur de retour de la commande. Par exemple, vous pouvez exécuter une commande Unix, un script ou d'autres commandes qui ne peuvent pas être directement exécutées dans le nœud.
Ce chapitre vous montrera comment exécuter des commandes externes, créer et communiquer avec les enfants et mettre fin aux enfants. Le but est de vous donner une idée de la façon de terminer une série de tâches en dehors du processus de nœud. Exécuter des commandes externes Lorsque vous devez exécuter une commande shell externe ou un exécutable, vous pouvez utiliser le module Child_Process pour l'importer comme ceci: La copie de code est la suivante: var child_process = require ('child_process') Ensuite, vous pouvez utiliser la fonction Exec dans le module pour exécuter des commandes externes: La copie de code est la suivante: var exec = child_process.exec; exec (commande, rappel); Le premier paramètre d'EXEC est la chaîne de commande shell que vous vous préparez à exécuter, et le deuxième paramètre est une fonction de rappel. Cette fonction de rappel sera appelée lorsque Exec aura terminé l'exécution de commandes externes ou une erreur se produit. La fonction de rappel a trois paramètres: Erreur, Stdout, STDERR, voir l'exemple suivant: La copie de code est la suivante: exec ('ls', fonction (err, stdout, stderr) { // Remarque du traducteur: Si vous utilisez Windows, vous pouvez le changer en commande Windows, tel que DIR, et je ne le répéterai pas plus tard. }); Si une erreur se produit, le premier paramètre sera une instance de la classe d'erreur. Si le premier paramètre ne contient pas d'erreur, le deuxième paramètre STDOUT contiendra la sortie standard de la commande. Le dernier paramètre contient une sortie d'erreur liée à la commande. Listing 8-1 montre un exemple plus complexe de l'exécution de commandes externes Listing 8-1: Exécuter des commandes externes (code source: Chapitre8 / 01_External_Command.js) La copie de code est la suivante: // importe la fonction exec du module child_process var exec = require ('child_process'). exec; // appelle la commande "Cat * .js | wc -l" exec ('cat * .js | wc l', fonction (err, stdout, stderr) {// ligne 4 // La commande sort ou l'appel échoue if (err) { // n'a pas réussi à démarrer un processus externe console.log ('child_process exit, le code d'erreur est:', err.code); retour; } } Dans la quatrième ligne, nous passons "Cat * .js | wc -l" comme premier paramètre à Exec. Vous pouvez également essayer n'importe quelle autre commande, tant que la commande que vous avez utilisée dans le shell est OK. Ensuite, prenez une fonction de rappel comme le deuxième paramètre, qui sera appelé lorsqu'une erreur se produit ou que le processus enfant se termine. Vous pouvez également transmettre un troisième paramètre facultatif avant la fonction de rappel, qui contient certaines options de configuration, telles que: La copie de code est la suivante: var exec = require ('child_process'). exec; Var Options = { Timeout: 1000, Killsignal: 'Sigkill' }; exec ('cat * .js | wc l', options, fonction (err, stdout, stderr) { //… }); Les paramètres qui peuvent être utilisés sont: 1.CWD - Le répertoire actuel, vous pouvez spécifier le répertoire de travail actuel. 2. Encodage - Le format de codage du contenu de sortie du processus de l'enfant, la valeur par défaut est "UTF8", c'est-à-dire le codage UTF-8. Si la sortie du processus enfant n'est pas UTF8, vous pouvez utiliser ce paramètre pour le définir. Les formats d'encodage pris en charge sont: La copie de code est la suivante: ascii UTF8 UCS2 base64 Si vous souhaitez en savoir plus sur ces formats d'encodage pris en charge par le nœud, veuillez vous référer au chapitre 4 "Utilisation du tampon pour traiter, codager et décoder les données binaires". 1.Timeout - Le délai d'exécution de la commande en millisecondes, la valeur par défaut est 0, c'est-à-dire qu'il n'y a pas de limite et attendez que le processus de l'enfant se termine. 2.MaxBuffer - Spécifie le nombre maximum d'octets autorisés par le flux STDOUT et le flux Stderr. Si la valeur maximale est atteinte, le processus enfant sera tué. La valeur par défaut est 200 * 1024. 3. Killsignal - Le signal final envoyé au processus de l'enfant lorsque le délai d'expiration ou le cache de sortie atteint la valeur maximale. La valeur par défaut est "Sigterm", qui enverra un signal de terminaison au processus de l'enfant. Ceci est généralement utilisé pour mettre fin au processus de manière ordonnée. Lorsque vous utilisez des signaux SIGTERM, le processus peut également traiter ou réécrire le comportement par défaut du processeur de signal après l'avoir reçu. Si le processus cible en a besoin, vous pouvez y transmettre d'autres signaux en même temps (comme SIGUSR1). Vous pouvez également choisir d'envoyer un signal Sigkill, qui sera traité par le système d'exploitation et forcera le processus enfant immédiatement, afin que toute opération de nettoyage du processus enfant ne soit pas effectuée. Si vous souhaitez contrôler davantage la fin du processus, vous pouvez utiliser la commande child_process.spawn, qui sera introduite plus tard. 1.EVN - Spécifie la variable d'environnement transmise au processus de l'enfant. La valeur par défaut est NULL, ce qui signifie que le processus enfant héritera des variables d'environnement de tous les processus parents avant sa création. Remarque: En utilisant l'option KillSignal, vous pouvez envoyer des signaux au processus cible en tant que chaîne. Dans le nœud, le signal existe sous forme de chaîne. Voici une liste des signaux UNIX et des opérations par défaut correspondantes: Vous voudrez peut-être fournir un ensemble de variables d'environnement parent extensibles pour le processus enfant. Si vous modifiez directement l'objet Process.env, vous modifierez les variables d'environnement de tous les modules du processus de nœud, ce qui causera beaucoup de problèmes. L'alternative consiste à créer un nouvel objet et à copier tous les paramètres dans Process.env, voir l'exemple 8-2: Listing 8-2: Utilisez des variables d'environnement paramétré pour exécuter les commandes (code source: Chapitre8 / 02_ENV_VARS_AUGment.js) La copie de code est la suivante: var env = process.env, varname, EnvCopy = {}, exec = require ('child_process'). exec; // Copier le processus.env à envcopy pour (vaname dans ev) { EnvCopy [varName] = Env [varName]; } // Définissez des variables personnalisées EnvCopy ['Custom Env Var1'] = 'Some Value'; EnvCopy ['Custom Env Var2'] = 'une autre valeur'; // Exécuter des commandes à l'aide de process.env et de variables personnalisées exec ('ls la', {Env: Envcopy}, fonction (err, stdout, stderr) { if (err) {throw err; } console.log ('stdout:', stdout); console.log ('stderr:', stderr); } Dans l'exemple ci-dessus, une variable ENVCOPY est créée pour enregistrer les variables d'environnement. Il copie d'abord les variables d'environnement du processus de nœud à partir de process.env, puis ajoute ou remplace certaines variables d'environnement qui doivent être modifiées, et transmet enfin Encopy en tant que paramètre de variable d'environnement à la fonction EXEC et exécute des commandes externes. N'oubliez pas que les variables d'environnement sont passées entre les processus via le système d'exploitation et que tous les types de valeurs de variables d'environnement arrivent au processus de l'enfant en tant que chaînes. Par exemple, si le processus parent prend le numéro 123 en tant que variable d'environnement, le processus de l'enfant recevra "123" en tant que chaîne. Dans l'exemple suivant, deux scripts de nœud seront créés dans le même répertoire: parent.js et child.js. Le premier script appellera le second. Créons ces deux fichiers: Listing 8-3: le processus parent définit les variables d'environnement (Chapitre8 / 03_environment_number_parent.js) La copie de code est la suivante: var exec = require ('child_process'). exec; exec ('node child.js', {env: {nombre: 123}}, fonction (err, stdout, stderr) { if (err) {throw err; } console.log ('stdout: / n', stdout); console.log ('stderr: / n', stderr); }); Enregistrez ce code sur parent.js. Ce qui suit est le code source du processus de l'enfant et les enregistrer sur Child.js (voir l'exemple 8-4) Exemple 8-4: Variables de l'environnement des parses de sous-processus (Chapitre8 / 04_environment_number_child.js) La copie de code est la suivante: var numéro = process.env.number; console.log (typeof (nombre)); // → "String" numéro = parseInt (numéro, 10); console.log (typeof (nombre)); // → "numéro" Après avoir enregistré ce fichier en tant que child.js, vous pouvez exécuter la commande suivante dans ce répertoire: La copie de code est la suivante: $ nœud parent.js Vous verrez la sortie suivante: La copie de code est la suivante: sdtou: chaîne nombre stderr: Comme vous pouvez le voir, bien que le processus parent passe une variable d'environnement numérique, le processus de l'enfant le reçoit en tant que chaîne (voir la deuxième ligne de sortie), et dans la troisième ligne, vous analysez la chaîne en un nombre. Générer un processus d'enfant Comme vous pouvez le voir, vous pouvez utiliser la fonction child_process.exec () pour démarrer un processus externe et appeler votre fonction de rappel à la fin du processus. Ceci est très simple à utiliser, mais il y a des inconvénients: 1. En plus d'utiliser les paramètres de ligne de commande et les variables d'environnement, exec () ne peut pas communiquer avec les processus enfants. 2. La sortie du processus de l'enfant est mise en cache, vous ne pouvez donc pas la diffuser, elle peut manquer de mémoire Heureusement, le module Child_process de Node de Node permet de granularité plus fine de contrôler le début, l'arrêt et d'autres opérations conventionnelles des processus enfants. Vous pouvez démarrer un nouveau processus enfant dans la demande. Node fournit un canal de communication bidirectionnel, permettant aux processus parent et enfant d'envoyer et de recevoir des données de chaîne les uns des autres. Le processus parent peut également avoir des opérations de gestion pour le processus de l'enfant, envoyer des signaux au processus de l'enfant et fermer avec force le processus de l'enfant. Créer un processus d'enfant Vous pouvez utiliser la fonction child_process.spawn pour créer un nouveau processus enfant, voir l'exemple 8-5: Exemple 8-5: générer un processus enfant. (Chapitre8 / 05_Spawning_child.js) La copie de code est la suivante: // importe la fonction d'apparition du module Child_process var spawn = require ('child_process'). Spawn; // générer des processus enfants utilisés pour exécuter la commande "Tail -f /var/log/system.log" var child = spawn ('tail', ['-f', '/var/log/system.log']); Le code ci-dessus génère un processus enfant utilisé pour exécuter les commandes de queue et prend "-f" et "/bar/log/system.log" comme paramètres. La commande tail surveillera le fichier /var/log/system.og (si présent), puis publiera toutes les nouvelles données annexées au flux de sortie standard STDOUT. La fonction Spawn renvoie un objet Child Process, qui est un objet de pointeur, encapsulant l'interface d'accès du processus réel. Dans cet exemple, nous attribuons ce nouveau descripteur à une variable appelée enfant. Écoutez les données des processus enfants Toute poignée de processus enfant contenant l'attribut stdout prendra la sortie standard du processus enfant en tant qu'objet de flux. Vous pouvez lier l'événement de données sur cet objet Stream, de sorte que chaque fois qu'un bloc de données est disponible, la fonction de rappel correspondante sera appelée, consultez l'exemple suivant: La copie de code est la suivante: // Imprime la sortie du processus de l'enfant à la console child.stout.on ('data', fonction (data) { console.log ('sortie de la queue:' + données); }); Chaque fois que le processus de l'enfant diffuse des données à la sortie standard STDOUT, le processus parent est informé et imprime les données de la console. En plus de la sortie standard, le processus a un autre flux de sortie par défaut: le flux d'erreur standard, qui est généralement utilisé pour produire des informations d'erreur. Dans cet exemple, si le fichier /var/log/system.log n'existe pas, le processus de queue publiera un message similaire à ce qui suit: "/var/log/system.log: aucun fichier ou répertoire de ce type". En écoutant le flux Stderr, le processus parent sera informé lorsque cette erreur se produira. Le processus parent peut écouter des flux d'erreur standard comme celui-ci: La copie de code est la suivante: child.stderr.on ('data', fonction (data) { Console.log ('Tail Error Sortie:', Data); }); La propriété Stderr, comme STDOUT, est également un flux en lecture seule. Chaque fois qu'un processus d'enfant diffuse des données dans le flux d'erreur standard, le processus parent sera informé et les données de sortie. Envoyer des données au processus enfant En plus de recevoir des données du flux de sortie du processus de l'enfant, le processus parent peut également écrire des données dans l'entrée standard du processus de l'enfant via la propriété ChildPones.Stdin pour envoyer des données au processus enfant. Le processus de l'enfant peut écouter les données d'entrée standard via le flux de lecture de processus. L'exemple 8-6 créera un programme contenant les fonctions suivantes: 1. + 1 Application: une application simple qui peut recevoir des entiers de l'entrée standard, puis les ajouter, puis publier le résultat après l'ajout du flux de sortie standard. En tant que service informatique simple, cette application simule le processus de nœud en tant que service externe qui peut effectuer des tâches spécifiques. 2. Testez le client de l'application +1, envoyez un entier aléatoire, puis publiez le résultat. Utilisé pour démontrer comment le processus de nœud génère un processus enfant, puis lui permet d'effectuer des tâches spécifiques. Utilisez le code suivant dans l'exemple 8-6 pour créer un fichier nommé plus_one.js: Exemple 8-6: +1 Application (Chapitre8 / 06_Plus_one.js) La copie de code est la suivante: // Restaurez le flux d'entrée standard qui est interrompu par défaut process.stdin.resume (); process.stdin.on ('data', fonction (data) { Numéro var; essayer { // analyser les données d'entrée dans un entier Number = paSeInt (data.toString (), 10); // +1 nombre + = 1; // Résultat de sortie process.stdout.write (nombre + "/ n"); } catch (err) { process.stderr.write (err.message + "/ n"); } }); Dans le code ci-dessus, nous attendons les données du flux d'entrée standard STDIN. Chaque fois que des données sont disponibles, nous supposons qu'il s'agit d'un entier et de les analyser dans une variable entière, puis d'ajouter 1, et de sortir le résultat au flux de sortie standard. Vous pouvez exécuter ce programme via la commande suivante: La copie de code est la suivante: $ node plus_one.js Après l'exécution, le programme commence à attendre l'entrée. Si vous entrez un entier et appuyez sur Entrée, vous verrez un nombre après avoir été ajouté 1 pour être affiché à l'écran. Vous pouvez quitter le programme en appuyant sur Ctrl-C. Un client de test Vous souhaitez maintenant créer un processus de nœud pour utiliser les services informatiques fournis par la précédente "application +1". Créez d'abord un fichier nommé plus_one_test.js, voir l'exemple 8-7: Exemple 8-7: Test +1 Application (Chapter8 / 07_Plus_one_test.js) La copie de code est la suivante: var spawn = require ('child_process'). Spawn; // générer un processus enfant pour exécuter +1 application var child = spawn ('node', ['Plus_one.js']); // appelle la fonction chaque seconde setInterval (function () { // Créer un nombre aléatoire inférieur à 10.000 Var Number = Math.Floor (Math.Random () * 10000); // Envoyez ce numéro au processus de l'enfant: child.stdin.write (nombre + "/ n"); // Obtenez la réponse du processus enfant et imprimez-le: child.stout.once ('data', fonction (data) { Console.log ('Enfant a répondu à' + numéro + 'avec:' + data); }); }, 1000); child.stderr.on ('data', fonction (data) { process.stdout.write (données); }); De la première ligne à la quatrième ligne, un processus enfant est démarré pour exécuter l'application "+1", puis les opérations suivantes sont effectuées chaque seconde en utilisant la fonction SetInterval: 1. Créez un nouveau nombre aléatoire moins de 10000 2. Passez ce numéro en tant que chaîne au processus enfant 3. Attendez que le processus de l'enfant réponde à une chaîne 4. Parce que vous souhaitez recevoir un seul numéro à la fois, vous devez utiliser child.stout.once au lieu de child.stdout.on. Si ce dernier est utilisé, une fonction de rappel d'un événement de données sera enregistrée toutes les 1 secondes. Chaque fonction de rappel enregistrée sera exécutée lorsque le STDOUT du processus enfant reçoit des données. De cette façon, vous constaterez que le même résultat de calcul sera sorti plusieurs fois. Ce comportement est évidemment faux. Recevoir des notifications lorsque le processus des enfants sort Lorsque le processus de l'enfant sortira, l'événement de sortie sera licencié. L'exemple 8-8 montre comment l'écouter: Exemple 8-8: Écoutez l'événement de sortie du processus de l'enfant (Chapitre8 / 09_LISTEN_CHILD_EXIT.JS) La copie de code est la suivante: var spawn = require ('child_process'). Spawn; // générer un processus enfant pour exécuter la commande "ls -la" var child = spawn ('ls', ['-la']); child.stout.on ('data', fonction (data) { console.log ('Données de l'enfant:' + données); }); // Lorsque le processus de l'enfant sort: <strong> child.on ('exit', fonction (code) { console.log («processus enfant terminé avec le code» + code); }); </strong> Dans les dernières lignes de code noir, le processus parent utilise l'événement de sortie du processus de l'enfant pour écouter son événement de sortie. Lorsque l'événement se produit, la console affiche la sortie correspondante. Le code de sortie du processus enfant sera transmis à la fonction de rappel comme premier paramètre. Certains programmes utilisent un code de sortie non 0 pour représenter un certain état de défaillance. Par exemple, si vous essayez d'exécuter la commande "ls al cliquez cliquer filename.txt", mais le répertoire actuel n'a pas ce fichier, vous obtiendrez un code de sortie avec une valeur de 1, voir l'exemple 8-9: Exemple 8-9: Obtenez le code de sortie du processus de l'enfant (Chapitre8 / 10_child_exit_code.js) La copie de code est la suivante: var spawn = require ('child_process'). Spawn; // Générer le processus enfant et exécuter la commande "ls DOES_NOT_EXIST.txt" var child = Spawn ('ls', ['DOED_NOT_EXIST.txt']); // Lorsque le processus de l'enfant sort child.on ('exit', fonction (code) { console.log («processus enfant terminé avec le code» + code); }); Dans cet exemple, l'événement de sortie déclenche la fonction de rappel et transmet le code de sortie du processus de l'enfant comme le premier paramètre. Si le processus de l'enfant quitte anormalement en raison de la mort d'un signal, le code de signal correspondant sera transmis à la fonction de rappel comme un deuxième paramètre, comme dans l'exemple 8-10: Listing 8-10: Obtenez le signal de sortie du processus de l'enfant (Chapitre8 / 11_child_exit_signal.js) La copie de code est la suivante: var spawn = require ('child_process'). Spawn; // générer un processus enfant et exécuter la commande "Sleep 10" var child = Spawn ('Sleep', ['10']); setTimeout (function () { child.kill (); }, 1000); child.on ('exit', fonction (code, signal) { if (code) { console.log («processus enfant terminé avec le code» + code); } else if (signal) { Console.log («Le processus de l'enfant s'est terminé à cause du signal» + signal); } }); Dans cet exemple, un processus d'enfant a commencé à effectuer un sommeil de 10 secondes, mais un signal Sigkill est envoyé au processus de l'enfant avant 10 secondes, ce qui entraînera la sortie suivante: La copie de code est la suivante: Le processus de l'enfant s'est terminé à cause du signal SIGTERM Envoyer un signal et tuer le processus Dans cette section, vous apprendrez à utiliser des signaux pour gérer les sous-processus. Les signaux sont un moyen facile pour un processus parent de communiquer avec les enfants et même de tuer des enfants. Différents codes de signal représentent différentes significations, et il existe de nombreux signaux, dont certains sont les plus courants utilisés pour tuer les processus. Si un processus reçoit un signal qu'il ne sait pas comment gérer, le programme sera interrompu par exception. Certains signaux sont traités par des sous-processus, tandis que d'autres ne peuvent être traités que par le système d'exploitation. Généralement, vous pouvez utiliser la méthode Child.Kill pour envoyer un signal au processus de l'enfant et envoyer un signal SIGTERM par défaut: La copie de code est la suivante: var spawn = require ('child_process'). Spawn; var child = Spawn ('Sleep', ['10']); setTimeout (function () { child.kill (); }, 1000); Vous pouvez également envoyer un signal spécifique en transmettant une chaîne identifiant le signal comme le seul paramètre de la méthode de tuer: La copie de code est la suivante: child.kill ('Sigusr2'); Il convient de noter que bien que le nom de cette méthode soit tué, le signal envoyé ne tue pas nécessairement le processus de l'enfant. Si l'enfant a traité le signal, le comportement du signal par défaut a été écrasé. Les sous-processus écrits en nœud peuvent réécrire la définition du processeur de signal comme ce qui suit: La copie de code est la suivante: process.on ('Sigusr2', fonction () { Console.log ('Got a Sigusr2 Signal'); }); Maintenant, vous avez défini le processeur de signal SIGUSR2. Lorsque votre processus reçoit à nouveau le signal SIGUSR2, il ne sera pas tué, mais émet plutôt la phrase "a obtenu un signal SIGUSR2". En utilisant ce mécanisme, vous pouvez concevoir un moyen simple de communiquer avec le processus de l'enfant ou même de le commander. Bien qu'il ne soit pas aussi riche que d'utiliser une entrée standard, cette méthode est beaucoup plus simple. résumé Dans ce chapitre, nous avons appris à utiliser la méthode child_process.exec pour exécuter des commandes externes. De cette façon, nous pouvons transmettre des paramètres au processus de l'enfant au lieu d'utiliser des paramètres de ligne de commande, mais à la place de définir les variables d'environnement. J'ai également appris à générer des processus enfants en appelant la méthode child_process.spawn pour appeler des commandes externes. De cette façon, vous pouvez utiliser des flux d'entrée et des flux de sortie pour communiquer avec les processus enfants, ou utiliser des signaux pour communiquer avec les processus enfants et tuer les processus.