Was dieser Artikel Ihnen bringt, ist die Analyse (Codebeispiele) des child_process-Moduls und des Cluster-Moduls in node.js. Ich hoffe, dass es für Sie hilfreich ist.
Node folgt einem Single-Threaded-Single-Process-Modell. Der Single-Thread von Node bedeutet, dass die js-Engine nur eine Instanz hat und im Hauptthread von nodejs ausgeführt wird. Gleichzeitig verarbeitet Node asynchrone Vorgänge wie IO ereignisgesteuert. Der Single-Thread-Modus des Knotens verwaltet nur einen Haupt-Thread, was die Kosten für den Wechsel zwischen Threads erheblich reduziert.
Der einzelne Thread des Knotens verhindert jedoch, dass CPU-intensive Vorgänge auf dem Hauptthread ausgeführt werden, andernfalls wird der Hauptthread blockiert. Für CPU-intensive Vorgänge können über child_process unabhängige untergeordnete Prozesse im Knoten erstellt werden. Der untergeordnete Prozess kann eine externe Anwendung oder ein untergeordnetes Programm sein an den übergeordneten Prozess zurückgegeben.
Darüber hinaus ist der Knoten Single-Threaded und wird als einzelner Prozess ausgeführt, sodass er keine Multi-Core-CPUs und andere Ressourcen nutzen kann. Um Ressourcen wie Multi-Core-CPUs zu planen, stellt der Knoten auch einen Cluster bereit Modul zur Nutzung der Ressourcen von Multi-Core-CPUs, wodurch es möglich wird, Lastaufgaben durch eine Reihe von Knoten-Unterprozessen zu bewältigen und gleichzeitig einen bestimmten Lastausgleich sicherzustellen. Dieser Artikel beginnt mit dem Verständnis des einzelnen Threads und einzelnen Prozesses des Knotens und stellt das Modul child_process und das Clustermodul vor
Das erste zu verstehende Konzept ist das Knoten Single-Threaded- und Single-Process-Modus. Im Vergleich zu den Multithread-Modi anderer Sprachen reduziert der einzelne Thread des Knotens die Kosten für den Wechsel zwischen Threads, und es besteht keine Notwendigkeit, beim Schreiben von Knotencode Sperren und Thread-Pool-Probleme zu berücksichtigen. Der vom Knoten deklarierte Single-Threaded-Modus eignet sich besser für E/A-intensive Vorgänge als andere Sprachen. Eine klassische Frage lautet also:
Ist der Knoten wirklich Single-Threaded?
Wenn es um Knoten geht, fallen uns sofort Wörter wie Single-Threaded, asynchrones IO und ereignisgesteuert ein. Als Erstes muss geklärt werden, ob der Knoten wirklich Single-Threaded ist. Wenn es Single-Threaded ist, wo werden dann asynchrone E/A- und geplante Ereignisse (setTimeout, setInterval usw.) ausgeführt?
Genau genommen ist der Knoten kein Single-Thread. Es gibt viele Arten von Threads im Knoten, darunter:
JS-Engine-Ausführungsthread
Timer-Thread (setTimeout, setInterval)
Asynchroner http-Thread (Ajax)
....
Was wir normalerweise Single-Thread nennen, bedeutet, dass es nur einen im gibt Die Node-JS-Engine läuft im Hauptthread. Andere asynchrone E/A- und ereignisgesteuerte verwandte Threads verwenden libuv, um interne Thread-Pools und Thread-Planung zu implementieren. In libv gibt es eine Ereignisschleife, und das Umschalten durch die Ereignisschleife kann einen ähnlichen Effekt wie Multithreading erzielen. Einfach ausgedrückt verwaltet Event Loop einen Ausführungsstapel und eine Ereigniswarteschlange. Wenn im aktuellen Ausführungsstapel asynchrone E/A- und Timerfunktionen gefunden werden, werden diese asynchronen Rückruffunktionen in die Ereigniswarteschlange gestellt. Nachdem die Ausführung des aktuellen Ausführungsstapels abgeschlossen ist, werden die asynchronen Rückruffunktionen in der Ereigniswarteschlange in einer bestimmten Reihenfolge aus der Ereigniswarteschlange ausgeführt.
In der obigen Abbildung wird vom Ausführungsstapel bis zur Ereigniswarteschlange und schließlich die Rückruffunktion ausgeführt Eine bestimmte Reihenfolge in der Ereigniswarteschlange. Der gesamte Prozess ist eine vereinfachte Version der Ereignisschleife. Darüber hinaus wird bei der Ausführung der Rückruffunktion auch ein Ausführungsstapel generiert. Asynchrone Funktionen können innerhalb der Rückruffunktion verschachtelt sein, was bedeutet, dass der Ausführungsstapel verschachtelt ist.
Mit anderen Worten bedeutet der einzelne Thread im Knoten, dass die js-Engine nur auf dem einzigen Hauptthread ausgeführt wird. Andere asynchrone Vorgänge müssen ebenfalls über die Ereignisschleife von libv ausgeführt werden . Thread-Kontextwechsel und Thread-Pool-Planung. Threads sind die kleinsten Prozesse, daher ist der Knoten auch ein einzelner Prozess. Dies erklärt, warum der Knoten Single-Threaded und Single-Process ist.
Da der Knoten ein einzelner Prozess ist, muss ein Problem vorliegen, das heißt, er kann Ressourcen wie die CPU nicht vollständig nutzen. Node stellt das Modul child_process bereit, um untergeordnete Prozesse zu implementieren und so ein Multiprozessmodell im weitesten Sinne zu realisieren. Durch das Modul child_process kann der Modus eines Hauptprozesses und mehrerer Unterprozesse realisiert werden. Der Hauptprozess wird als Masterprozess bezeichnet, und der Unterprozess wird auch als Arbeitsprozess bezeichnet. Im Unterprozess können Sie nicht nur andere Knotenprogramme aufrufen, sondern auch Nicht-Knoten-Programme und Shell-Befehle usw. ausführen. Nach der Ausführung des Unterprozesses kehrt dieser in Form eines Streams oder Rückrufs zurück.
child_process bietet 4 Methoden zum Erstellen neuer untergeordneter Prozesse: spawn, execFile, exec und fork. Alle Methoden sind asynchron und die Unterschiede zwischen diesen vier Methoden können anhand eines Bildes beschrieben werden.
Das obige Bild kann die Unterschiede zwischen diesen vier Methoden zeigen. Wir können auch kurz die Unterschiede zwischen diesen vier Methoden vorstellen.
spawn: Ein Nicht-Knoten-Programm wird im untergeordneten Prozess ausgeführt. Nachdem ein Satz Parameter bereitgestellt wurde, wird das Ausführungsergebnis in Form eines Streams zurückgegeben.
execFile: Ein Nicht-Knoten-Programm wird im untergeordneten Prozess ausgeführt. Nachdem ein Satz Parameter bereitgestellt wurde, wird das Ausführungsergebnis in Form von a zurückgegeben Rückruf.
exec: Der untergeordnete Prozess führt ein Nicht-Knoten-Programm aus, übergibt eine Zeichenfolge von Shell-Befehlen und das Ergebnis wird anschließend in Form eines Rückrufs zurückgegeben Ausführung, die sich von execFile unterscheidet
Die Sache ist, dass exec eine Reihe von Shell-Befehlen direkt ausführen kann.
Fork: Der untergeordnete Prozess führt das Knotenprogramm aus, nachdem er einen Satz Parameter bereitgestellt hat. Im Gegensatz zu Spawn wird das Ausführungsergebnis zurückgegeben. Fork generiert untergeordnete Prozesse, die nur Knotenanwendungen ausführen können. In den folgenden Abschnitten werden diese Methoden im Detail vorgestellt.
Wir vergleichen zunächst die Ähnlichkeiten zwischen diesen beiden Methoden:
Eine Nicht-Knoten-Anwendung wird ausgeführt und das Ausführungsergebnis wird in Form einer Rückruffunktion zurückgegeben.
Der Unterschied ist:
exec ist ein Shell-Befehl, der direkt ausgeführt wird, während execFile eine Anwendung ist, die ausgeführt wird
Echo ist beispielsweise ein integrierter Befehl des UNIX-Systems. Wir können ihn direkt auf der Befehlszeile ausführen:
echo hello world
Als Ergebnis: Hallo Welt.
wird in der Befehlszeile gedruckt.Erstellen Sie eine neue main.js-Datei. Wenn Sie die exec-Methode verwenden möchten, schreiben Sie in die Datei:
rrreeFühren Sie dieses main js aus, das Ergebnis ist Hallo Welt. Wir haben festgestellt, dass der erste Parameter von exec dem Shell-Befehl völlig ähnlich ist.
let cp=require('child_process'); cp.exec('echo hello world',function(err,stdout){ console.log(stdout); });
execFile ähnelt dem Ausführen einer Anwendung namens echo und der anschließenden Übergabe von Parametern. execFlie sucht im Pfad von „process.env.PATH“ nach einer Anwendung mit dem Namen „echo“ und führt sie aus, nachdem es gefunden wurde. Der Standardpfad „process.env.PATH“ enthält „usr/local/bin“, und dieses Programm mit dem Namen „echo“ befindet sich im Verzeichnis „usr/local/bin“, übergibt die beiden Parameter hello und world und kehrt nach der Ausführung zurück.
Wie bei exec ist es äußerst unsicher, eine Shell direkt auszuführen:
let cp=require('child_process'); cp.execFile('echo',['hello','world'],function(err,stdout){ console.log(stdout); });
Das ist möglich verwenden exec Bei direkter Ausführung löscht rm -rf die Dateien im aktuellen Verzeichnis. Exec ist genau wie die Befehlszeile. Nach der Ausführung treten sehr hohe Sicherheitsprobleme auf. ExecFile ist jedoch anders:
echo hello world;rm -rf
erkennt die Sicherheit der Ausführung der tatsächlich übergebenen Parameter in den Parametern Wenn ein Sicherheitsproblem vorliegt, wird eine Ausnahme ausgelöst. Zusätzlich zu execFile können Spawn und Fork die Shell nicht direkt ausführen und sind daher sicherer.
Spawn wird auch zum Ausführen von Nicht-Knoten-Anwendungen verwendet und kann die Shell nicht direkt ausführen. Das Ergebnis der Spawn-Ausführung der Anwendung ist nicht einmalig Ergebnis nach Abschluss der Ausführung. Die Ausgabe erfolgt in Form eines Streams. Für die Ausgabe großer Datenmengen kann die Verwendung von Speicher in Form von Streams eingeführt werden.
Nehmen wir als Beispiel das Sortieren und Deduplizieren einer Datei:
Im obigen Bilddiagramm wird die Eingabe gelesen Zuerst gibt es in der TXT-Datei unsortierten Text. Die Sortierfunktion kann über das Sortierprogramm implementiert werden, und die Ausgabe ist aabc. Schließlich kann das Uniq-Programm verwendet werden, um Duplikate zu erhalten. Wir können die Eingabe und Ausgabe des Spawn-Streams verwenden, um die oben genannten Funktionen zu implementieren:
execFile('echo',['hello','world',';rm -rf'])
Nach der Ausführung wird das Endergebnis in process.stdout eingegeben. Wenn die Datei „input.txt“ groß ist, kann die Eingabe und Ausgabe in Form von Streams die Speichernutzung erheblich reduzieren. Durch das Festlegen eines Puffers kann die Speichernutzung reduziert und gleichzeitig die Eingabe- und Ausgabeeffizienz verbessert werden.
In JavaScript wird HTML im Hinblick auf die Verarbeitung einer großen Anzahl von Berechnungsaufgaben durch Webarbeit implementiert, wodurch die Aufgabe vom Hauptthread getrennt wird. Um dieses Problem zu lösen, wird im Knoten eine integrierte Kommunikation zwischen dem übergeordneten Prozess und dem untergeordneten Prozess verwendet, wodurch der Druck auf Big-Data-Operationen verringert wird. Die Fork-Methode wird im Knoten bereitgestellt. Durch die Fork-Methode wird das Knotenprogramm in einem separaten Prozess ausgeführt. Durch die Kommunikation zwischen Vater und Sohn akzeptiert der untergeordnete Prozess die Informationen des übergeordneten Prozesses und gibt die Ausführungsergebnisse an den übergeordneten Prozess zurück .
Mit der Fork-Methode kann ein IPC-Kanal zwischen dem übergeordneten Prozess und dem untergeordneten Prozess geöffnet werden, wodurch die Nachrichtenkommunikation zwischen verschiedenen Knotenprozessen ermöglicht wird.
Im untergeordneten Prozess:
Empfangen und senden Sie Nachrichten über die Mechanismen von Process.on('message') und Process.send().
Im übergeordneten Prozess:
Empfangen und senden Sie über die Mechanismen child.on('message') undprocess.send() Information.
Spezifisches Beispiel in child.js:
let cp=require('child_process'); let cat=cp.spawn('cat',['input.txt']); let sort=cp.spawn('sort'); let uniq=cp.spawn('uniq'); cat.stdout.pipe(sort.stdin); sort.stdout.pipe(uniq.stdin); uniq.stdout.pipe(process.stdout); console.log(process.stdout);
In parent.js:
process.on('message',function(msg){ process.send(msg) })
Beim Ausführen von parent.js wird in der Befehlszeile Folgendes ausgegeben: Ich habe eine Nachricht erhalten: „Hallo Welt“
Um die Kommunikation zwischen Vater und Sohn zu unterbrechen, können Sie die IPC-Kommunikation zwischen Vater und Sohn trennen, indem Sie im übergeordneten Prozess Folgendes aufrufen:
let cp=require('child_process'); let child=cp.fork('./child'); child.on('message',function(msg){ console.log('got a message is',msg); }); child.send('hello world');
.
exec、execFile、spawn和fork执行的子进程都是默认异步的,子进程的运行不会阻塞主进程。除此之外,child_process模块同样也提供了execFileSync、spawnSync和execSync来实现同步的方式执行子进程。
cluster意为集成,集成了两个方面,第一个方面就是集成了child_process.fork方法创建node子进程的方式,第二个方面就是集成了根据多核CPU创建子进程后,自动控制负载均衡的方式。
我们从官网的例子来看:
const cluster = require('cluster'); const http = require('http'); const numCPUs = require('os').cpus().length; if (cluster.isMaster) { console.log(`主进程 ${process.pid} 正在运行`); // 衍生工作进程。 for (let i = 0; i { console.log(`工作进程 ${worker.process.pid} 已退出`); }); } else { // 工作进程可以共享任何 TCP 连接。 // 在本例子中,共享的是一个 HTTP 服务器。 http.createServer((req, res) => { res.writeHead(200); res.end('你好世界\n'); }).listen(8000); console.log(`工作进程 ${process.pid} 已启动`); }
最后输出的结果为:
$ node server.js 主进程 3596 正在运行 工作进程 4324 已启动 工作进程 4520 已启动 工作进程 6056 已启动 工作进程 5644 已启动
我们将master称为主进程,而worker进程称为工作进程,利用cluster模块,使用node封装好的API、IPC通道和调度机可以非常简单的创建包括一个master进程下HTTP代理服务器 + 多个worker进程多个HTTP应用服务器的架构。
本文首先介绍了node的单线程和单进程模式,接着从单线程的缺陷触发,介绍了node中如何实现子进程的方法,对比了child_process模块中几种不同的子进程生成方案,最后简单介绍了内置的可以实现子进程以及CPU进程负载均衡的内置集成模块cluster。
相关推荐:
Node.js中关于多进程模块Cluster的详细介绍以及如何使用
Das obige ist der detaillierte Inhalt vonAnalyse des Child_Process-Moduls und des Cluster-Moduls in node.js (Codebeispiel). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!