One place for hosting & domains

      starting at only

      $20/Month

      So verwenden Sie ps, kill und schön zum Verwalten von Prozessen unter Linux


      Einführung


      Auf einem Linux-Server werden wie auf jedem anderen Computer, mit dem Sie möglicherweise vertraut sind, Anwendungen ausgeführt. Auf dem Computer werden diese als „Prozesse“ bezeichnet.

      Während Linux die Verwaltung auf niedriger Ebene hinter den Kulissen im Lebenszyklus eines Prozesses übernimmt, benötigen Sie eine Möglichkeit zur Interaktion mit dem Betriebssystem, um es von einer höheren Ebene aus zu verwalten.

      In diesem Leitfaden werden wir einige einfache Aspekte der Prozessverwaltung erörtern. Linux bietet eine reichliche Sammlung von Tools für diesen Zweck.

      Wir werden diese Ideen auf einem Ubuntu 12.04 VPS untersuchen, aber jede moderne Linux-Distribution funktioniert auf ähnliche Weise.

      So zeigen Sie laufende Prozesse unter Linux an


      top


      Der einfachste Weg, um herauszufinden, welche Prozesse auf Ihrem Server ausgeführt werden, besteht darin, den Befehl top auszuführen:

      top***
      
      top - 15:14:40 bis 46 min, 1 Benutzer, Lastdurchschnitt: 0,00, 0,01, 0,05 Aufgaben: 56 insgesamt, 1 laufend, 55 inaktiv, 0 gestoppt, 0 Zombie Cpu(s):  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st Mem: 1019600k gesamt, 316576k gebraucht, 703024k frei, 7652k Puffer Swap: 0k insgesamt, 0k verwendet, 0k frei, 258976k zwischengespeichert   PID USER PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND               1 root      20   0 24188 2120 1300 S  0.0  0.2   0:00.56 init                   2 root      20   0     0    0    0 S  0.0  0.0   0:00.00 kthreadd               3 root      20   0     0    0    0 S  0.0  0.0   0:00.07 ksoftirqd/0            6 root      RT   0     0    0    0 S  0.0  0.0   0:00.00 migration/0            7 root      RT   0     0    0    0 S  0.0  0.0   0:00.03 watchdog/0             8 root       0 -20     0    0    0 S  0.0  0.0   0:00.00 cpuset                 9 root       0 -20     0    0    0 S  0.0  0.0   0:00.00 khelper               10 root      20   0     0    0    0 S  0.0  0.0   0:00.00 kdevtmpfs
      

      Der oberste Informationsblock enthält Systemstatistiken wie die Systemlast und die Gesamtzahl der Aufgaben.

      Sie können leicht erkennen, dass 1 Prozess ausgeführt wird und 55 Prozesse inaktiv sind (auch bekannt als inaktiv/ohne CPU-Ressourcen).

      Der untere Teil enthält die laufenden Prozesse und ihre Nutzungsstatistiken.

      htop


      Eine verbesserte Version von top namens htop ist in den Repositorys verfügbar. Installieren Sie sie mit diesem Befehl:

      sudo apt-get install htop
      

      Wenn wir den Befehl htop ausführen, sehen wir, dass es eine benutzerfreundlichere Anzeige gibt:

      htop***
      
        Mem[|||||||||||           49/995MB]     Durchschnittslast: 0.00 0.03 0.05   CPU[                          0.0%]     Aufgaben: 21, 3 thr; 1 laufend   Swp[                         0/0MB]     Betriebszeit: 00:58:11   PID USER PRI  NI  VIRT   RES   SHR S CPU% MEM%   TIME+  Command  1259 root       20   0 25660  1880  1368 R  0.0  0.2  0:00.06 htop     1 root       20   0 24188  2120  1300 S  0.0  0.2  0:00.56 /sbin/init   311 root       20   0 17224   636   440 S  0.0  0.1  0:00.07 upstart-udev-brid   314 root       20   0 21592  1280   760 S  0.0  0.1  0:00.06 /sbin/udevd --dae   389 messagebu  20   0 23808   688   444 S  0.0  0.1  0:00.01 dbus-daemon --sys   407 syslog     20   0  243M  1404  1080 S  0.0  0.1  0:00.02 rsyslogd -c5   408 syslog     20   0  243M  1404  1080 S  0.0  0.1  0:00.00 rsyslogd -c5   409 syslog     20   0  243M  1404  1080 S  0.0  0.1  0:00.00 rsyslogd -c5   406 syslog     20   0  243M  1404  1080 S  0.0  0.1  0:00.04 rsyslogd -c5   553 root       20   0 15180   400   204 S  0.0  0.0  0:00.01 upstart-socket-br
      

      Sie können hier mehr über die Verwendung von top und htop erfahren.

      Verwendung von ps zum Auflisten von Prozessen


      Sowohl top als auch htop bieten eine schöne Benutzeroberfläche, um laufende Prozesse zu sehen, die einem grafischen Aufgabenmanager ähneln.

      Diese Tools sind jedoch nicht immer flexibel genug, um alle Szenarien angemessen zu behandeln. Ein leistungsfähiger Befehl namens ps ist oft die Antwort auf diese Probleme.

      Wenn er ohne Argumente aufgerufen wird, kann die Ausgabe etwas fehlerhafter sein:

      ps***
      
        PID TTY          TIME CMD  1017 pts/0    00:00:00 bash  1262 pts/0    00:00:00 ps
      

      Diese Ausgabe zeigt alle mit dem aktuellen Benutzer und der Terminalsitzung verknüpften Prozesse an. Dies ist sinnvoll, da wir derzeit nur bash und ps mit diesem Terminal ausführen.

      Um ein vollständigeres Bild der Prozesse auf diesem System zu erhalten, können wir Folgendes ausführen:

      ps aux***
      
      USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND root         1  0.0  0.2  24188  2120 ?        Ss   14:28   0:00 /sbin/initroot         2  0.0  0.0      0     0 ?        S    14:28   0:00 [kthreadd] root         3  0.0  0.0      0     0 ?        S    14:28   0:00 [ksoftirqd/0] root         6  0.0  0.0      0     0 ?        S    14:28   0:00 [migration/0] root         7  0.0  0.0      0     0 ?        S    14:28   0:00 [watchdog/0] root         8  0.0  0.0      0     0 ?        S<   14:28   0:00 [cpuset] root         9  0.0  0.0      0     0 ?        S<   14:28   0:00 [khelper] . . .
      

      Diese Optionen weisen ps an, Prozesse, die allen Benutzern gehören (unabhängig von ihrer Terminalzuordnung), in einem benutzerfreundlichen Format anzuzeigen.

      Um eine Baumansicht zu sehen, in der hierarchische Beziehungen illustriert werden, können wir den Befehl mit diesen Optionen ausführen:

      ps axjf***
      
       PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND     0     2     0     0 ?           -1 S        0   0:00 [kthreadd]     2     3     0     0 ?           -1 S        0   0:00  _ [ksoftirqd/0]     2     6     0     0 ?           -1 S        0   0:00  _ [migration/0]     2     7     0     0 ?           -1 S        0   0:00  _ [watchdog/0]     2     8     0     0 ?           -1 S<       0   0:00  _ [cpuset]     2     9     0     0 ?           -1 S<       0   0:00  _ [khelper]     2    10     0     0 ?           -1 S        0   0:00  _ [kdevtmpfs]     2    11     0     0 ?           -1 S<       0   0:00  _ [netns] . . .
      

      Wie Sie sehen können, wird der Prozess kthreadd als übergeordnetes Element des Prozesses ksoftirqd/0 und der anderen Prozesse angezeigt.

      Eine Anmerkung zu Prozess-IDs


      In Linux- und Unix-ähnlichen Systemen wird jedem Prozess einer Prozess-ID oder PID zugewiesen. So identifiziert und verfolgt das Betriebssystem Prozesse.

      Eine schnelle Möglichkeit zum Abrufen der PID eines Prozesses ist mit dem Befehl pgrep:

      pgrep bash***
      
      1017
      

      Dadurch wird die Prozess-ID einfach abfragt und zurückgegeben.

      Der erste beim Booten erzeugte Prozess namens init erhält die PID „1“.

      pgrep init***
      
      1
      

      Dieser Prozess ist dann dafür verantwortlich, jeden anderen Prozess auf dem System zu erzeugen. Die späteren Prozesse erhalten größere PID-Nummern.

      Das übergeordnete Element eines Prozesses ist der Prozess, der für das Ablegen verantwortlich war. Übergeordnete Prozesse verfügen über eine PPID, die Sie in den Spaltenüberschriften vieler Prozessverwaltungsanwendungen sehen können, einschließlich top, htop und ps.

      Jede Kommunikation zwischen dem Benutzer und dem Betriebssystem über Prozesse umfasst die Übersetzung zwischen Prozessnamen und PIDs zu einem bestimmten Zeitpunkt während des Vorgangs. Aus diesem Grund teilen Dienstprogramme Ihnen die PID mit.

      Übergeordnete-untergeordnete Beziehungen


      Das Erstellen eines untergeordneten Prozesses erfolgt in zwei Schritten: fork(), das einen neuen Adressraum erstellt und die Ressourcen des übergeordneten Elements per Copy-on-Write kopiert, um dem untergeordneten Prozess zur Verfügung zu stehen; und exec(), das eine ausführbare Datei in den Adressraum lädt und ausführt.

      Für den Fall, dass ein untergeordneter Prozess vor seinem übergeordneten Prozess beendet wird, wird der untergeordnete Prozess zu einem Zombie, bis der übergeordnete Prozess Informationen darüber gesammelt oder dem Kernel angezeigt hat, dass er diese Informationen nicht benötigt. Die Ressourcen aus dem untergeordneten Prozess werden dann freigegeben. Wenn der übergeordnete Prozess jedoch vor dem untergeordneten Prozess beendet wird, wird der untergeordnete Prozess von init übernommen, obwohl er auch einem anderen Prozess neu zugewiesen werden kann.

      So senden Sie Prozesssignale in Linux


      Alle Prozesse in Linux reagieren auf Signale. Signale sind eine Methode auf Betriebssystemebene, mit der Programme angewiesen werden, ihr Verhalten zu beenden oder zu ändern.

      So senden Sie Prozesssignale nach PID


      Die häufigste Art, Signale an ein Programm weiterzuleiten, ist mit dem Befehl kill.

      Wie Sie möglicherweise erwarten, besteht die Standardfunktion dieses Dienstprogramms darin, zu versuchen, einen Prozess zu beenden:

      kill PID_of_target_process

      Dadurch wird das TERM-Signal an den Prozess gesendet. Das TERM-Signal weist den Prozess an, zu beenden. Dadurch kann das Programm Reinigungsvorgänge durchführen und reibungslos beenden.

      Wenn sich das Programm schlecht verhält und bei Erhalt des TERM-Signals nicht beendet wird, können wir das Signal durch Weiterleiten des KILL-Signals eskalieren:

      kill -KILL PID_of_target_process

      Dies ist ein spezielles Signal, das nicht an das Programm gesendet wird.

      Stattdessen wird es dem Betriebssystem-Kernel übergeben, der den Prozess herunterschaltet. Dies wird verwendet, um Programme zu umgehen, die die an sie gesendeten Signale ignorieren.

      Jedem Signal ist eine Nummer zugeordnet, die anstelle des Namens übergeben werden kann. Beispielsweise können Sie „-15“ anstelle von „-TERM“ und „-9“ anstelle von „-KILL“ übergeben.

      So verwenden Sie Signale für andere Zwecke


      Signale werden nicht nur zum Herunterfahren von Programmen verwendet. Sie können auch verwendet werden, um andere Aktionen auszuführen.

      Beispielsweise werden viele Daemons neu gestartet, wenn sie das HUP– oder Auflegesignal erhalten. Apache ist ein Programm, das so funktioniert.

      sudo kill -HUP pid_of_apache

      Der obige Befehl führt dazu, dass Apache seine Konfigurationsdatei neu lädt und Inhalte wiederbelebt.

      Sie können alle Signale auflisten, die mit kill gesendet werden können, indem Sie Folgendes eingeben:

      kill -l***
      
      1) SIGHUP    2) SIGINT   3) SIGQUIT  4) SIGILL   5) SIGTRAP  6) SIGABRT  7) SIGBUS   8) SIGFPE   9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM . . .
      

      So senden Sie Prozesssignale nach Name


      Obwohl die konventionelle Art des Sendens von Signalen durch die Verwendung von PIDs ist, gibt es auch Methoden, dies mit regulären Prozessnamen zu tun.

      Der Befehl pkill funktioniert fast genau so wie kill, operiert jedoch stattdessen auf einem Prozessnamen:

      pkill -9 ping
      

      Der obige Befehl ist das Äquivalent von:

      kill -9 `pgrep ping`
      

      Wenn Sie ein Signal an jede Instanz eines bestimmten Prozesses senden möchten, können Sie den Befehl killall verwenden:

      killall firefox
      

      Der obige Befehl sendet das TERM-Signal an jede Instanz von Firefox, das auf dem Computer ausgeführt wird.

      So passen Sie Prozessprioritäten an


      Oft möchten Sie anpassen, welchen Prozessen in einer Serverumgebung Priorität eingeräumt wird.

      Einige Prozesse können als geschäftskritisch für Ihre Situation angesehen werden, während andere ausgeführt werden können, wenn Ressourcen übrig bleiben.

      Linux kontrolliert die Priorität durch einen Wert namens niceness.

      Hohe Prioritätsaufgaben werden als weniger nett angesehen, da sie auch keine Ressourcen teilen. Prozesse mit niedriger Priorität sind dagegen nett, weil sie darauf bestehen, nur minimale Ressourcen zu verbrauchen.

      Als wir am Anfang des Artikels top ausgeführt haben, gab es eine Spalte mit der Bezeichnung „NI“. Dies ist der nette Wert des Prozesses:

      top***
      
      Aufgaben: 56 insgesamt, 1 laufend, 55 inaktiv, 0 gestoppt, 0 Zombie Cpu(s):  0.0%us,  0.3%sy,  0.0%ni, 99.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st Mem:   1019600k insgesamt,   324496k verwendet,   695104k frei,     8512k Puffer Swap:   0k insgesamt,   0k verwendet,   0k frei,    264812k zwischengespeichert   PID-BENUTZER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND            1635 root      20   0 17300 1200  920 R  0.3  0.1   0:00.01 top                    1 root      20   0 24188 2120 1300 S  0,0  0,2   0:00,56 init                   2 root      20   0     0    0    0 S  0.0  0.0   0:00.00 kthreadd               3 root      20   0     0    0    0 S  0.0  0.0   0:00.11 ksoftirqd/0
      

      Nette Werte können je nach System zwischen „-19/-20“ (höchste Priorität) und „19/20“ (niedrigste Priorität) liegen.

      Um ein Programm mit einem bestimmten netten Wert auszuführen, können wir den Befehl nice verwenden:

      nice -n 15 command_to_execute

      Dies funktioniert nur, wenn ein neues Programm gestartet wird.

      Um den netten Wert eines Programms zu ändern, das bereits ausgeführt wird, verwenden wir ein Tool namens renice:

      renice 0 PID_to_prioritize

      Hinweis: Während nice zwangsläufig mit einem Befehlsnamen funktioniert, ruft renice die Prozess-PID auf

      Zusammenfassung


      Die Prozessverwaltung ist ein Thema, das für neue Benutzer manchmal schwer zu verstehen ist, da sich die verwendeten Tools von ihren grafischen Gegenstücken unterscheiden.

      Die Ideen sind jedoch vertraut und intuitiv und werden mit ein wenig Übung zur Gewohnheit. Da Prozesse an allem beteiligt sind, was Sie mit einem Computersystem tun, ist es eine wesentliche Fähigkeit, zu lernen, wie man sie effektiv steuert.

      Von Justin Ellingwood



      Source link

      Starten von untergeordneten Prozessen in Node.js


      Der Autor hat den COVID-19 Relief Fund dazu ausgewählt, eine Spende im Rahmen des Programms Write for DOnations zu erhalten.

      Einführung

      Wenn ein Benutzer ein einzelnes Node.js-Programm ausführt, wird es als einzelner Betriebssystem-(OS)-Prozess ausgeführt, der die Instanz des laufenden Programms darstellt. In diesem Prozess führt Node.js Programme auf einem einzigen Thread aus. Wie bereits in dieser Serie im Tutorial So schreiben Sie asynchronen Code in Node.js erwähnt können Operationen, die eine lange Zeit zur Ausführung in JavaScript benötigen, den Node.js-Thread blockieren und die Ausführung anderen Codes verzögern, da nur ein Thread in einem einzelnen Prozess ausgeführt werden kann. Eine Schlüsselstrategie zur Umgehung dieses Problems besteht darin, einen Kindprozess – oder einen durch einen anderen Prozess erstellten Prozess – bei lang laufenden Aufgaben zu starten. Wenn ein neuer Prozess gestartet wird, kann das Betriebssystem Multiprocessing-Techniken einsetzen, um sicherzustellen, dass der hauptsächliche Node.js-Prozess und der zusätzliche Kindprozess gleichzeitig ausgeführt werden.

      Node.js enthält das child_process-Modul, das über Funktionen zur Erstellung neuer Prozesse verfügt. Neben der Bewältigung von langwierigen Aufgaben kann dieses Modul auch eine Schnittstelle mit dem OS bilden und Shell-Befehle ausführen. Systemadministratoren können Node.js zum Ausführen von Shell-Befehlen verwenden, um ihre Operationen als Node.js-Modul anstelle von Shell-Skripten zu strukturieren und zu pflegen.

      In diesem Tutorial erstellen Sie Kindprozesse bei der Ausführung einer Reihe von Node.js-Beispielanwendungen. Sie erstellen Prozesse mit dem child_process-Modul durch Abrufen der Ergebnisse eines Kindprozesses über einen Puffer oder eine Zeichenfolge mit der exec()-Funktion und dann aus einem Datenstream mit der spawn()-Funktion. Abschließend verwenden fork() zur Erstellung eines Kindprozesses eines anderen Node.js-Programms, mit dem Sie während der Ausführung kommunizieren können. Um diese Konzepte zu illustrieren, erstellen Sie ein Programm zur Auflistung des Inhalts eines Verzeichnisses, ein Programm zur Auffindung von Dateien und einen Webserver mit mehreren Endpunkten.

      Voraussetzungen

      Schritt 1 — Erstellen eines Kindprozesses mit exec()

      Entwickler erstellen üblicherweise Kindprozesse zur Ausführung von Befehlen in ihrem Betriebssystem, wenn sie die Ausgabe ihrer Node.js-Programme mit einer Shell manipulieren müssen, so wie zum Beispiel bei der Shell-Weiterleitung oder -Umleitung. Die exec()-Funktion in Node.js erstellt einen neuen Shell-Prozess und führt in dieser Shell einen Befehl aus. Die Ausgabe des Befehls wird in einem Puffer im Arbeitsspeicher aufbewahrt, den Sie über eine in exec() übergebene Callback-Funktion akzeptieren können.

      Beginnen wir mit der Erstellung unserer ersten Kindprozesse in Node.js. Zuerst müssen wir unsere Codierungsumgebung einrichten, um die Skripte, die wir in diesem Tutorial erstellen, zu speichern. Erstellen Sie im Terminal einen Ordner namens child-processes:

      Geben Sie diesen Ordner im Terminal mit dem cd-Befehl ein:

      Erstellen Sie eine neue Datei namens listFiles.js und öffnen Sie die Datei in einem Texteditor. In diesem Tutorial verwenden wir nano, einen Terminaltexteditor.

      Wir schreiben ein Node.js-Modul, das die exec()-Funktion zur Ausführung des ls-Befehls verwendet. Der ls-Befehl listet die Dateien und Ordner in einem Verzeichnis. Dieses Programm nimmt die Ausgabe des ls-Befehls und zeigt sie dem Benutzer an.

      Fügen Sie im Texteditor den folgenden Code hinzu:

      ~/child-processes/listFiles.js

      const { exec } = require('child_process');
      
      exec('ls -lh', (error, stdout, stderr) => {
        if (error) {
          console.error(`error: ${error.message}`);
          return;
        }
      
        if (stderr) {
          console.error(`stderr: ${stderr}`);
          return;
        }
      
        console.log(`stdout:n${stdout}`);
      });
      

      Wir importieren zunächst den exec()-Befehl aus dem child_process-Modul unter Verwendung der JavaScript-Destrukturierung. Nach dem Import verwenden wir die exec()-Funktion. Das erste Argument ist der Befehl, den wir ausführen möchten. In diesem Fall ist es ls -lh, der alle Dateien und Ordner im aktuellen Verzeichnis im Langformat listet, mit einer Gesamtdateigröße in visuell lesbaren Einheiten am Anfang der Ausgabe.

      Das zweite Argument ist eine Callback-Funktion mit drei Parametern: error, stdout und stderr. Wenn die Ausführung des Befehls fehlschlägt, erfasst error den entsprechenden Grund. Das kann vorkommen, wenn die Shell den Befehl, den Sie ausführen möchten, nicht finden kann. Wenn der Befehl erfolgreich ausgeführt wird, werden alle Daten, die er in den Standardausgabestream schreibt, in stdout erfasst, sowie alle Daten, die er an den Standardfehlerstream schreibt, in stderr erfasst.

      Anmerkung: Es ist wichtig, den Unterschied zwischen error und stderr im Auge zu behalten. Wenn die Ausführung des Befehls selbst fehlschlägt, erfasst error den Fehler. Wenn der Befehl ausgeführt wird, aber eine Ausgabe in den Fehlerstream zurückgibt, wird dies von stderr erfasst. Die stabilsten Node.js-Programme verarbeiten alle möglichen Ausgaben für einen untergeordneten Prozess.

      In unserer Callback-Funktion überprüfen wir zunächst, ob wir einen Fehler erhalten haben. Falls dem so ist, stellen wir die message des Fehlers (eine Eigenschaft des Error-Objekts) mit console.error() dar und beenden die Funktion mit return. Wir überprüfen dann, ob der Befehl eine Fehlermeldung und in dem Fall return ausgegeben hat. Wenn der Befehl erfolgreich ausgeführt wird, protokollieren wir seine Ausgabe in der Konsole mit console.log().

      Führen wir diese Datei aus, um sie in Aktion zu sehen. Speichern und schließen Sie nano, indem Sie STRG+X drücken.

      Zurück in Ihrem Terminal führen Sie nun Ihre Anwendung mit dem node-Befehl aus:

      In Ihrem Terminal wird die folgende Ausgabe angezeigt:

      Output

      stdout: total 4.0K -rw-rw-r-- 1 sammy sammy 280 Jul 27 16:35 listFiles.js

      In dieser wird der Inhalt des child-processes-Verzeichnisses in langer Form aufgelistet, zusammen mit der Größe des Inhalts am Anfang. Ihre Ergebnisse haben anstelle von sammy Ihren eigenen Benutzer und Ihre Gruppe. Das zeigt, dass das listFiles.js-Programm den Shell-Befehl ls -lh erfolgreich ausgeführt hat.

      Schauen wir uns nun einen anderen Weg zur Ausführung gleichzeitiger Prozesse an. Das child_process-Modul von Node.js kann auch ausführbare Dateien mit der execFile()-Funktion ausführen. Der Hauptunterschied zwischen den Funktionen execFile() und exec() besteht darin, dass das erste Argument von execFile() nun ein Pfad zu einer ausführbaren Datei anstelle eines Befehls ist. Die Ausgabe der ausführbaren Datei wird in einem Puffer wie exec() gespeichert, auf den wir über eine Callback-Funktion mit error-, stdout– und stderr-Parametern zugreifen.

      Anmerkung: Skripte in Windows wie .bat– und .cmd-Dateien können nicht mit execFile() ausgeführt werden, da die Funktion beim Ausführen der Datei keine Shell erstellt. Unter Unix, Linux und MacOS benötigen ausführbare Skripte nicht immer eine Shell, um ausgeführt zu werden. Windows-Rechner benötigen jedoch eine Shell, um Skripte auszuführen. Um Skriptdateien unter Windows auszuführen, verwenden Sie exec(), da es eine neue Shell erstellt. Alternativ können Sie spawn() verwenden. Sie verwenden es später in diesem Schritt.

      Sie können jedoch .exe-Dateien in Windows erfolgreich mit execFile() ausführen. Die Beschränkung gilt nur für Skriptdateien, die eine Shell zur Ausführung benötigen.

      Beginnen wir mit dem Hinzufügen eines ausführbaren Skripts für execFile(). Wir schreiben ein Bash-Skript, das das Node.js-Logo von der Website von Node.js herunterlädt und es mit Base64 kodiert, um seine Daten in eine Zeichenfolge von ASCII-Zeichen zu konvertieren.

      Erstellen Sie eine neue Shell-Skriptdatei namens processNodejsImage.sh:

      • nano processNodejsImage.sh

      Schreiben Sie nun ein Skript, um das Bild herunterzuladen und mit base64 zu konvertieren:

      ~/child-processes/processNodejsImage.sh

      #!/bin/bash
      curl -s https://nodejs.org/static/images/logos/nodejs-new-pantone-black.svg > nodejs-logo.svg
      base64 nodejs-logo.svg
      

      Die erste Anweisung ist eine Shebang-Anweisung. Sie wird in Unix, Linux und MacOS verwendet, wenn wir eine Shell zur Ausführung unseres Skripts spezifizieren möchten. Die zweite Anweisung ist ein curl-Befehl. Das cURL utility, dessen Befehl curl ist, ist ein Befehlszeilentool, das Daten zu und von einem Server übertragen kann. Wir verwenden cURL, um das Node.js-Logo von der Website herunterzuladen. Dann verwenden wir Umleitung, um die heruntergeladenen Daten in einer neuen Datei nodejs-logo.svg zu speichern. Die letzte Anweisung verwendet das base64-Dienstprogramm zur Codierung der mit cURL heruntergeladenen Datei nodejs-logo.svg. Das Skript gibt dann die codierte Zeichenfolge an die Konsole aus.

      Speichern und schließen Sie, bevor Sie fortfahren.

      Damit unser Node-Programm das bash-Skript ausführen kann, müssen wir es ausführbar machen. Führen Sie dazu Folgendes aus:

      • chmod u+x processNodejsImage.sh

      Dadurch erhält Ihr aktueller Benutzer die Berechtigung, die Datei auszuführen.

      Mit unserem vorhandenen Skript können wir ein neues Node.js-Modul schreiben, um es auszuführen. Dieses Skript verwendet execFile(), um das Skript in einem untergeordneten Prozess auszuführen, wobei etwaige Fehler abgefangen werden und jede Ausgabe in der Konsole angezeigt wird.

      Erstellen Sie in Ihrem Terminal eine neue JavaScript-Datei namens getNodejsImage.js:

      Geben Sie den folgenden Code im Texteditor ein:

      ~/child-processes/getNodejsImage.js

      const { execFile } = require('child_process');
      
      execFile(__dirname + '/processNodejsImage.sh', (error, stdout, stderr) => {
        if (error) {
          console.error(`error: ${error.message}`);
          return;
        }
      
        if (stderr) {
          console.error(`stderr: ${stderr}`);
          return;
        }
      
        console.log(`stdout:n${stdout}`);
      });
      

      Wir verwenden JavaScript-Destrukturierung zum Importieren der execFile()-Funktion aus dem child_process-Modul. Dann verwenden wir diese Funktion, indem wir den Dateipfad als Vorname übergeben. __dirname enthält den Verzeichnispfad des Moduls, in dem es geschrieben ist. Node.js stellt die __dirname-Variable für ein Modul bereit, wenn das Modul ausgeführt wird. Durch die Verwendung von __dirname findet unser Skript immer die Datei processNodejsImage.sh unter verschiedenen Betriebssystemen,unabhängig davon, wo wir getNodejsImage.js ausführen. Beachten Sie, dass sich für unsere aktuelle Projekteinrichtung getNodejsImage.js und processNodejsImage.sh im gleichen Ordner befinden müssen.

      Das zweite Argument ist ein Callback mit den Parametern error, stdout und stderr. Wie bei unserem vorherigen Beispiel, in dem exec() verwendet wurde, überprüfen wir jede mögliche Ausgabe der Skriptdatei und protokollieren sie in der Konsole.

      Speichern Sie in Ihrem Texteditor diese Datei und verlassen Sie den Editor.

      Verwenden Sie in Ihrem Terminal node, um das Modul auszuführen:

      Bei Ausführung dieses Skripts wird eine Ausgabe wie diese erstellt:

      Output

      stdout: PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgNDQyLjQgMjcwLjkiPjxkZWZzPjxsaW5lYXJHcmFkaWVudCBpZD0iYiIgeDE9IjE4MC43IiB5MT0iODAuNyIge ...

      Beachten Sie, dass wir die Ausgabe in diesem Artikel aufgrund ihrer großen Größe verkürzt haben.

      Bevor der base64-Codierung des Bildes lädt processNodejsImage.sh es zunächst herunter. Sie können auch überprüfen, ob Sie das Bild heruntergeladen haben, indem Sie das aktuelle Verzeichnis inspizieren.

      Führen Sie listFiles.js aus, um die aktualisierte Liste von Dateien in unserem Verzeichnis zu finden:

      Das Skript zeigt Inhalte ähnlich wie folgende im Terminal an:

      Output

      stdout: total 20K -rw-rw-r-- 1 sammy sammy 316 Jul 27 17:56 getNodejsImage.js -rw-rw-r-- 1 sammy sammy 280 Jul 27 16:35 listFiles.js -rw-rw-r-- 1 sammy sammy 5.4K Jul 27 18:01 nodejs-logo.svg -rwxrw-r-- 1 sammy sammy 129 Jul 27 17:56 processNodejsImage.sh

      Wir haben nun processNodejsImage.sh erfolgreich als Kindprozess in Node.js mit der execFile()-Funktion ausgeführt.

      Die Funktionen exec() und execFile() können Befehle auf der Shell des Betriebssystems in einem Node.js-Kindprozess ausführen. Node.js bietet auch eine andere Methode mit ähnlicher Funktionalität, spawn(). Der Unterschied besteht darin, dass wir die Ausgabe der Shell-Befehle nicht auf einmal erhalten, sondern in Stücken über einen Stream. Im nächsten Abschnitt verwenden wir den spawn()-Befehl zur Erstellung eines untergeordneten Prozesses.

      Schritt 2 — Erstellen eines Kindprozesses mit spawn()

      Die spawn()-Funktion führt einen Befehl in einem Prozess aus. Diese Funktion gibt Daten über die Stream-API zurück. Um die Ausgabe des Kindprozesses zu erhalten, müssen wir daher auf Stream-Ereignisse lauschen.

      Streams in Node.js sind Instanzen von Ereignis-Emittern. Wenn Sie mehr über das Lauschen auf Ereignisse und die Grundlagen der Interaktion mit Streams erfahren möchten, können Sie unseren Leitfaden zur Verwendung von Ereigniss-Emittern in Node.js lesen.

      Es ist oft eine gute Idee, spawn() anstatt exec() oder execFile() zu wählen, wenn der Befehl, den Sie ausführen möchten, eine große Menge an Daten ausgeben kann. Bei einem Puffer, wie er von exec() und execFile() verwendet wird, werden alle verarbeiteten Daten im Arbeitsspeicher des Computers gespeichert. Bei großen Datenmengen kann hierbei die Systemleistung sinken. Bei einem Stream werden die Daten in kleinen Stücken verarbeitet und übertragen. Daher können Sie eine große Menge an Daten verarbeiten, ohne zu viel Arbeitsspeicher im selben Moment zu verwenden.

      Sehen wir uns an, wie wir spawn() zur Erstellung eines Kindprozesses verwenden können. Wir schreiben ein neues Node.js-Modul, das einen Kindprozess erstellt, um den Befehl find auszuführen. Wir verwenden den Befehl find , um alle Dateien im aktuellen Verzeichnis aufzulisten.

      Erstellen Sie eine neue Datei namens findFiles.js:

      Beginnen Sie in Ihrem Texteditor mit dem Aufruf des spawn()-Befehls:

      ~/child-processes/findFiles.js

      const { spawn } = require('child_process');
      
      const child = spawn('find', ['.']);
      

      Wir haben zunächst die spawn()-Funktion aus dem child_process-Modul importiert. Dann haben wir die spawn()-Funktion aufgerufen, um einen Kindprozess zu erstellen, der den Befehl find ausführt. Wir halten den Verweis auf den Prozess in der child-Variable, die wir zum Lauschen seiner gestreamten Ereignisse verwenden.

      Das erste Argument in spawn() ist der auszuführende Befehl, in diesem Fall find. Das zweite Argument ist ein Array, das die Argumente für den ausgeführten Befehl enthält. In diesem Fall weisen wir Node.js an, den Befehl find mit dem Argument ., auszuführen. Dadurch wird der Befehl veranlasst, alle Dateien im aktuellen Verzeichnis zu finden. Der äquivalente Befehl im Terminal ist find ..

      Mit den Funktionen exec() und execFile() haben wir die Argumente zusammen mit dem Befehl in einer Zeichenfolge geschrieben. Bei spawn() müssen jedoch alle Argumente für Befehle in das Array eingegeben werden. Das liegt daran, dass spawn(), im Gegensatz zu exec() und execFile(), keine neue Shell erstellt, bevor ein Prozess ausgeführt wird. Um Befehle mit ihren Argumenten in einer einzelnen Zeichenfolge zu haben, ist es auch erforderlich, das Node.js eine neue Shell erstellt.

      Wir fahren mit unserem Modul fort, indem wir Listener für die Ausgabe des Befehls hinzufügen. Fügen Sie die folgenden hervorgehobenen Zeilen hinzu:

      ~/child-processes/findFiles.js

      const { spawn } = require('child_process');
      
      const child = spawn('find', ['.']);
      
      child.stdout.on('data', data => {
        console.log(`stdout:n${data}`);
      });
      
      child.stderr.on('data', data => {
        console.error(`stderr: ${data}`);
      });
      

      Befehle können Daten entweder im stdout-Stream oder im stderr-Stream zurückgeben. Daher fügen Sie Listener für beide hinzu. Sie können Listener hinzufügen, indem Sie die on()-Methode der Objekte jedes Streams aufrufen. Das data-Ereignis aus den Streams gibt uns die Ausgabe des Befehls an diesen Stream. Wann immer wir Daten über einen Stream erhalten, protokollieren wir diese in der Konsole.

      Dann lauschen wird auf zwei andere Ereignisse: das error-Ereignis, wenn der Befehl nicht ausgeführt oder unterbrochen wird, und das close-Ereignis, wenn der Befehl die Ausführung beendet hat und damit den Stream schließt.

      Schließen Sie im Texteditor das Node.js-Modul ab, indem Sie die folgenden hervorgehobenen Zeilen schreiben:

      ~/child-processes/findFiles.js

      const { spawn } = require('child_process');
      
      const child = spawn('find', ['.']);
      
      child.stdout.on('data', (data) => {
        console.log(`stdout:n${data}`);
      });
      
      child.stderr.on('data', (data) => {
        console.error(`stderr: ${data}`);
      });
      
      child.on('error', (error) => {
        console.error(`error: ${error.message}`);
      });
      
      child.on('close', (code) => {
        console.log(`child process exited with code ${code}`);
      });
      

      Für die error– und close-Ereignisse haben Sie einen Listener direkt in der child-Variable eingerichtet. Wenn beim Lauschen auf error-Ereignisse ein Fehler auftritt, stellt Node.js ein Error-Objekt bereit. In diesem Fall protokollieren Sie die message-Eigenschaft des Fehlers.

      Beim Lauschen auf das close-Ereignis stellt Node.js den Exit-Code des Befehls bereit. Ein Exit-Code gibt an, ob der Befehl erfolgreich ausgeführt wurde oder nicht. Wenn ein Befehl ohne Fehler ausgeführt wird, gibt er den geringmöglichsten Wert für einen Exit-Code zurück: 0. Wenn er mit einem Fehler ausgeführt wird, wird ein Code ungleich Null zurückgegeben.

      Das Modul ist komplett. Speichern und schließen Sie nano mit STRG+X.

      Führen Sie nun den Code mit dem node-Befehl aus:

      Nach der Ausführung finden Sie die folgende Ausgabe:

      Output

      stdout: . ./findFiles.js ./listFiles.js ./nodejs-logo.svg ./processNodejsImage.sh ./getNodejsImage.js child process exited with code 0

      Wir finden eine Liste aller Dateien in unserem aktuellen Verzeichnis und den Exit-Code des Befehls, der 0 ist, da die Ausführung erfolgreich war. Unser aktuelles Verzeichnis hat nur eine kleine Anzahl von Dateien. Würden wir diesen Code in unserem Stammverzeichnis ausführen, würde unser Programm jede einzelne Datei in jedem zugänglichen Ordner für unseren Benutzer auflisten. Die Verwendung der spawn()-Funktion ist ideal, da sie eine potenziell so große Ausgabe hat, und weil ihre Streams nicht so viel Arbeitsspeicher benötigen wie ein großer Puffer.

      Bisher haben wir Funktionen zur Erstellung von Kindprozessen verwendet, um externe Befehle in unserem Betriebssystem auszuführen. Node.js bietet auch die Möglichkeit, einen Kindprozess zu erstellen, der andere Node.js-Programme ausführt. Im nächsten Abschnitt verwenden wir die fork()-Funktion zum Erstellen eines Kindprozesses für ein Node.js-Modul.

      Schritt 3 — Erstellen eines Kindprozesses mit fork()

      Node.js bietet die fork()-Funktion, eine Variante von spawn(), um einen Kindprozess zu erstellen, der gleichzeitig ein Node.js-Prozess ist. Der Hauptvorteil der Verwendung von fork() zur Erstellung eines Node.js-Prozesses anstelle von spawn() oder exec() besteht darin, dass fork() die Kommunikation zwischen dem Eltern- und dem Kindprozess ermöglicht.

      Mit fork() kann ein Elternprozess nicht nur Daten aus dem Kindprozess abrufen, sondern auch Nachrichten an den laufenden Kindprozess senden. Ebenso kann der Kindprozess Nachrichten an den Elternprozess senden.

      Sehen wir uns ein Beispiel an, bei dem die Verwendung von fork() zur Erstellung eines neuen Node.js-Kindprozesses die Leistung unserer Anwendung verbessern kann. Node.js-Programme werden in einem einzelnen Prozess ausgeführt. Daher stoppen CPU-intensive Aufgaben wie das Iterieren über große Schleifen oder das Parsing großer JSON-Dateien die Ausführung von anderem JavaScript-Code. Für bestimmte Anwendungen ist dies keine tragfähige Option. Wenn ein Webserver blockiert ist, kann er keine neuen eingehenden Anfragen verarbeiten, bis der blockierende Code seine Ausführung abgeschlossen hat.

      Wir sehen uns das in der Praxis an, indem wir einen Webserver mit zwei Endpunkten erstellen. Ein Endpunkt nimmt eine langsame Berechnung vor, die den Node.js-Prozess blockiert. Der andere Endpunkt gibt ein JSON-Objekt zurück, das hello sagt.

      Erstellen Sie zunächst eine neue Datei namens httpServer.js, die den Code für unseren HTTP-Server haben wird:

      Wir beginnen mit der Einrichtung des HTTP-Servers. Dazu gehört das Importieren des http-Moduls, die Erstellung einer Request Listener-Funktion, die Erstellung eines Server-Objekts und das Lauschen auf Anfragen an das Server-Objekt. Wenn Sie mehr über die Erstellung von HTTP-Servern in Node.js erfahren möchten oder eine Auffrischung zum Thema wünschen, können Sie unseren Leitfaden zum Erstellen eines Web-Servers in Node.js mit dem HTTP-Modul lesen.

      Geben Sie den folgenden Code in Ihren Texteditor ein, um einen HTTP-Server einzurichten:

      ~/child-processes/httpServer.js

      const http = require('http');
      
      const host="localhost";
      const port = 8000;
      
      const requestListener = function (req, res) {};
      
      const server = http.createServer(requestListener);
      server.listen(port, host, () => {
        console.log(`Server is running on http://${host}:${port}`);
      });
      

      Dieser Code erstellt einen HTTP-Server, der unter http://localhost:8000 ausgeführt wird. Er verwendet Template-Literale, um diese URL dynamisch zu generieren.

      Als Nächstes schreiben wir eine absichtlich langsame Funktion, die in einer Schleife 5 Milliarden Mal zählt. Fügen Sie vor der Funktion requestListener() den folgenden Code hinzu:

      ~/child-processes/httpServer.js

      ...
      const port = 8000;
      
      const slowFunction = () => {
        let counter = 0;
        while (counter < 5000000000) {
          counter++;
        }
      
        return counter;
      }
      
      const requestListener = function (req, res) {};
      ...
      

      Dieser verwendet die Syntax der Pfeilfunktion, um eine while-Schleife zu erstellen, die bis 5000000000 zählt.

      Um dieses Modul abzuschließen, müssen wir der requestListener()-Funktion Code hinzufügen. Unsere Funktion ruft die slowFunction() auf dem Unterpfad auf und gibt eine kleine JSON-Nachricht für die andere zurück. Fügen Sie dem Modul folgenden Code hinzu:

      ~/child-processes/httpServer.js

      ...
      const requestListener = function (req, res) {
        if (req.url === '/total') {
          let slowResult = slowFunction();
          let message = `{"totalCount":${slowResult}}`;
      
          console.log('Returning /total results');
          res.setHeader('Content-Type', 'application/json');
          res.writeHead(200);
          res.end(message);
        } else if (req.url === '/hello') {
          console.log('Returning /hello results');
          res.setHeader('Content-Type', 'application/json');
          res.writeHead(200);
          res.end(`{"message":"hello"}`);
        }
      };
      ...
      

      Wenn der Benutzer den Server am Unterpfad /total erreicht, führen wir slowFunction() aus. Wenn wir auf den Unterpfad /hello treffen, geben wir diese JSON-Nachricht zurück: {"message":"hello"}.

      Speichern und schließen Sie die Datei, indem Sie STRG+X drücken.

      Zum Testen führen Sie dieses Server-Modul mit node aus:

      Wenn unser Server startet, zeigt die Konsole Folgendes an:

      Output

      Server is running on http://localhost:8000

      Um die Leistung unseres Moduls zu testen, öffnen Sie nun zwei zusätzliche Terminals. Verwenden Sie im ersten Terminal den curl-Befehl, um eine Anfrage an den /total-Endpunkt zu stellen, von dem wir erwarten, dass er langsam ist:

      • curl http://localhost:8000/total

      Verwenden Sie im anderen Terminal curl, um eine Anfrage an den /hello-Endpunkt wie folgt zu stellen:

      • curl http://localhost:8000/hello

      Die erste Anfrage gibt folgende JSON zurück:

      Output

      {"totalCount":5000000000}

      Die zweite Anfrage gibt diese JSON zurück:

      Output

      {"message":"hello"}

      Die Anfrage an /hello wurde erst nach der Anfrage an /total abgeschlossen. Die slowFunction() hat die Ausführung allen anderen Codes blockiert, während sie noch in ihrer Schleife war. Sie können dies überprüfen, indem Sie die Ausgabe des Node.js-Servers anschauen, die in Ihrem ursprünglichen Terminal protokolliert worden ist:

      Output

      Returning /total results Returning /hello results

      Um den blockierenden Code zu verarbeiten und gleichzeitig eingehende Anfragen zu akzeptieren, können wir den blockierenden Code mit fork() in einen Kindprozess verschieben. Wir verschieben den blockierenden Code in sein eigenes Modul. Der Node.js-Server erstellt dann einen Kindprozess, wenn jemand auf den /total-Endpunkt zugreift und lauscht auf Ergebnisse aus diesem Kindprozess.

      Refaktorieren Sie den Server, indem Sie zunächst ein neues Modul namens getCount.js erstellen, das slowFunction(): enthält:

      Geben Sie nun den Code für slowFunction() erneut ein:

      ~/child-processes/getCount.js

      const slowFunction = () => {
        let counter = 0;
        while (counter < 5000000000) {
          counter++;
        }
      
        return counter;
      }
      

      Da dieses Modul ein mit fork() erstellter untergeordneter Prozess ist, können wir auch Code hinzufügen, um mit dem übergeordneten Prozess zu kommunizieren, wenn slowFunction() die Verarbeitung abgeschlossen hat. Fügen Sie den folgenden Code-Block hinzu, der eine Nachricht an den Elternprozess mit der JSON zur Rückgabe an den Benutzer sendet:

      ~/child-processes/getCount.js

      const slowFunction = () => {
        let counter = 0;
        while (counter < 5000000000) {
          counter++;
        }
      
        return counter;
      }
      
      process.on('message', (message) => {
        if (message == 'START') {
          console.log('Child process received START message');
          let slowResult = slowFunction();
          let message = `{"totalCount":${slowResult}}`;
          process.send(message);
        }
      });
      

      Gehen wird diesen Code-Block durch. Die von fork() erstellten Nachrichten zwischen einem Eltern- und Kindprozess sind über das globale process-Objekt von Node.js zugänglich. Wir fügen der process-Variable einen Listener hinzu, um nach message-Ereignissen zu suchen. Sobald wir ein message-Ereignis erhalten, überprüfen wir, ob es das START-Ereignis ist. Unser Servercode sendet das START-Ereignis, wenn jemand auf den /total-Endpunkt zugreift. Nach dem Erhalt dieses Ereignisses führen wir slowFunction() aus und erstellen mit dem Ergebnis der Funktion eine JSON-Zeichenfolge. Wir verwenden process.send(), um eine Nachricht an den übergeordneten Prozess zu senden.

      Speichern und schließen Sie getCount.js, indem Sie STRG+X in nano eingeben.

      Wir ändern nun die Datei httpServer.js so, dass sie anstatt slowFunction() aufzurufen, einen Kindprozess erstellt, der getCount.js ausführt.

      Öffnen Sie httpServer.js erneut mit nano:

      Importieren Sie zunächst die fork()-Funktion aus dem child_process-Modul:

      ~/child-processes/httpServer.js

      const http = require('http');
      const { fork } = require('child_process');
      ...
      

      Als Nächstes entfernen wir die slowFunction() aus diesem Modul und ändern die requestListener()-Funktion, um einen Kindprozess zu erstellen. Ändern Sie den Code in Ihrer Datei, damit er so aussieht:

      ~/child-processes/httpServer.js

      ...
      const port = 8000;
      
      const requestListener = function (req, res) {
        if (req.url === '/total') {
          const child = fork(__dirname + '/getCount');
      
          child.on('message', (message) => {
            console.log('Returning /total results');
            res.setHeader('Content-Type', 'application/json');
            res.writeHead(200);
            res.end(message);
          });
      
          child.send('START');
        } else if (req.url === '/hello') {
          console.log('Returning /hello results');
          res.setHeader('Content-Type', 'application/json');
          res.writeHead(200);
          res.end(`{"message":"hello"}`);
        }
      };
      ...
      

      Wenn jemand zum Endpunkt /total geht, erstellen wir nun einen neuen Kindprozess mit fork(). Das Argument von fork() ist der Pfad zum Node.js-Modul. In diesem Fall ist es die getCount.js-Detei in unserem aktuellen Verzeichnis, die wir von __dirname erhalten. Der Verweis auf diesen Kindprozess wird in einer child-Variablen gespeichert.

      Dann fügen wir dem child-Objekt einen Listener hinzu. Dieser Listener erfasst alle Nachrichten, die der Kindprozess uns gibt. In diesem Fall gibt getCount.js eine JSON-Zeichenfolge mit der Gesamtzahl zurück, die von der while-Schleife gezählt wurde. Wenn wir diese Nachricht erhalten, senden wir die JSON an den Benutzer.

      Wir verwenden die send()-Funktion der child-Variablen, um die Nachricht zu übergeben. Dieses Programm sendet die Message START, mit der die Ausführung von slowFunction() im untergeordneten Prozess beginnt.

      Speichern und schließen Sie nano, indem Sie STRG+X drücken.

      Um die Verbesserung mit fork() auf HTTP-Server zu testen, beginnen Sie mit der Ausführung der httpServer.js-Datei mit node:

      Wie zuvor gibt sie beim Starten die folgende Nachricht aus:

      Output

      Server is running on http://localhost:8000

      Um den Server zu testen, benötigen wir so wie beim ersten Mal zwei weitere Terminals. Sie können diese erneut verwenden, wenn sie noch offen sind.

      Verwenden Sie im ersten Terminal den curl-Befehl, um eine Anfrage an den /total-Endpunkt zu stellen, deren Berechnung eine Weile dauert:

      • curl http://localhost:8000/total

      Verwenden Sie im anderen Terminal curl, um eine Anfrage an den /hello-Endpunkt zu stellen, der in kurzer Zeit reagiert:

      • curl http://localhost:8000/hello

      Die erste Anfrage gibt folgende JSON zurück:

      Output

      {"totalCount":5000000000}

      Die zweite Anfrage gibt diese JSON zurück:

      Output

      {"message":"hello"}

      Anders als beim ersten Versuch wird die zweite Anfrage an /hello sofort ausgeführt. Sie können dies bestätigen, indem Sie die Protokolle überprüfen, die folgendermaßen aussehen:

      Output

      Child process received START message Returning /hello results Returning /total results

      Diese Protokolle zeigen, dass die Anfrage für den /hello-Endpunkt nach Erstellung des untergeordneten Prozesses, aber vor Beendigung des untergeordneten Prozesses ausgeführt wurde.

      Da wir den blockierenden Code in einem Kindprozess mit fork() verschoben haben, konnte der Server nach wie vor auf andere Anfragen reagieren und anderen JavaScript-Code ausführen. Aufgrund der Fähigkeit der fork()-Funktion, Nachrichten zu übergeben, können wir kontrollieren, wann ein Kindprozess eine Aktivität beginnt, und wir können Daten von einem Kindprozess an einen Elternprozess zurückgeben.

      Zusammenfassung

      In diesem Artikel haben Sie verschiedene Funktionen zur Erstellung eines Kindprozesses in Node.js verwendet. Sie haben zunächst Kindprozesse mit exec() erstellt, um Shell-Befehle aus Node.js-Code auszuführen. Sie haben dann eine ausführbare Datei mit der execFile()-Funktion ausgeführt. Sie haben sich die Funktion spawn() angeschaut, die auch Befehle ausführen kann, Daten jedoch über einen Stream zurückgibt und anders als exec() und execFile() keine Shell startet. Abschließend haben Sie die Funktion fork() verwendet, um eine zweigleisige Kommunikation zwischen dem Eltern- und Kindprozess zu ermöglichen.

      Um mehr über das child_process-Modul zu erfahren, können Sie die Node.js-Dokumentation lesen. Wenn Sie Node.js weiter lernen möchten, können Sie zur Codieren in Node-Reihe zurückkehren oder Programmierprojekte und -einstellungen auf unserer Node-Themenseite durchsuchen.



      Source link