ホームページ  >  記事  >  ウェブフロントエンド  >  node.jsのchild_processモジュールとclusterモジュールの解析(コード例)

node.jsのchild_processモジュールとclusterモジュールの解析(コード例)

不言
不言オリジナル
2018-08-29 11:30:311654ブラウズ

この記事は、node.js の child_process モジュールとクラスター モジュールの分析 (コード例) を示しています。必要な方は参考にしていただければ幸いです。

ノードはシングルスレッドのシングルプロセスモデルに従います。ノードのシングルスレッドとは、JS エンジンが 1 つのインスタンスのみを持ち、nodejs のメインスレッドで実行されることを意味します。同時に、ノードは IO などの非同期操作を処理します。イベント駆動型の方法。ノードのシングルスレッド モードではメイン スレッドが 1 つだけ維持されるため、スレッド間の切り替えコストが大幅に削減されます。

ただし、ノードの単一スレッドにより、メインスレッドでの CPU 負荷の高い操作の実行が防止されます。そうしないと、メインスレッドがブロックされます。 CPU を集中的に使用する操作の場合、child_process を通じてノード内に独立した子プロセスを作成できます。親プロセスと子プロセスは、IPC を通じて通信し、子プロセスの実行後に結果を得ることができます。親プロセスに戻りました。

さらに、ノードはシングルスレッドで単一プロセスとして実行されるため、マルチコア CPU やその他のリソースを利用できません。マルチコア CPU やその他のリソースをスケジュールするために、ノードはクラスター モジュールも提供します。マルチコア CPU のリソースを使用してノード サブの文字列を渡すことができるようにします。プロセスは、一定の負荷分散を確保しながら負荷タスクを処理します。この記事は、ノードのシングル スレッドとシングル プロセスの理解から始まり、child_process モジュールとクラスター モジュールを紹介します

1. ノードのシングル スレッドとシングル プロセス

最初に理解する概念は、ノードのシングル スレッドとシングル プロセス モードです。他の言語のマルチスレッド モードと比較して、ノードのシングル スレッドはスレッド間の切り替えコストを削減し、ノード コードを記述するときにロックやスレッド プールの問題を考慮する必要がありません。ノードによって宣言されたシングルスレッド モードは、他の言語よりも IO 集中型の操作に適しています。古典的な質問は次のとおりです:

node は本当にシングルスレッドですか?

ノードに関して言えば、シングルスレッド、非同期 IO、イベント駆動などの言葉がすぐに思い浮かびます。最初に明確にする必要があるのは、ノードが本当にシングルスレッドであるかどうかです。シングルスレッドの場合、非同期 IO とスケジュールされたイベント (setTimeout、setInterval など) がどこで実行されるかということです。

厳密に言えば、ノードはシングルスレッドではありません。ノードには次のようなさまざまな種類のスレッドがあります:

  • js エンジン実行スレッド

  • タイマー スレッド (setTimeout、setInterval)

  • 非同期 http スレッド (ajax)

....

通常シングルスレッドと呼ばれるものは、メインスレッドで実行されているノード内に JS エンジンが 1 つだけあることを意味します。他の非同期 IO およびイベント駆動関連のスレッドは、libuv を使用して内部スレッド プールとスレッド スケジューリングを実装します。 libv にはイベント ループがあり、イベント ループを切り替えることでマルチスレッドと同様の効果を得ることができます。簡単に言うと、イベント ループは実行スタックとイベント キューを維持します。現在の実行スタックで非同期 IO 関数とタイマー関数が見つかった場合、これらの非同期コールバック関数はイベント キューに入れられます。現在の実行スタックの実行が完了すると、イベント キュー内の非同期コールバック関数がイベント キューから特定の順序で実行されます。

node.jsのchild_processモジュールとclusterモジュールの解析(コード例)

上図では、実行スタックからイベントキューに至り、最後にイベントキュー内でコールバック関数が特定の順序で実行されるまでのプロセス全体がイベントループの簡略化されたバージョンです。 。さらに、コールバック関数が実行されると、非同期関数がコールバック関数内にネストされる場合があります。これは、実行スタックがネストされることを意味します。

言い換えれば、ノード内の単一スレッドは、js エンジンが唯一のメインスレッドでのみ実行されることを意味し、マルチスレッドと同様のコンテキスト切り替えも libv のイベント ループを通じて実装されます。プールのスケジュール調整。スレッドは最小のプロセスであるため、ノードも単一のプロセスです。これは、ノードがシングルスレッドかつシングルプロセスである理由を説明します。

2. ノードのchild_processモジュールはマルチプロセスを実装します

ノードは単一プロセスであるため、CPUなどのリソースを十分に活用できないという問題が発生するはずです。 Nodeは子プロセスを実装するchild_processモジュールを提供し、広義のマルチプロセスモデルを実現します。 child_process モジュールを通じて、1 つのメインプロセスと複数のサブプロセスのモードを実現できます。メインプロセスはマスタープロセスと呼ばれ、サブプロセスは作業プロセスとも呼ばれます。サブプロセスでは、他のノードプログラムを呼び出すだけでなく、非ノードプログラムやシェルコマンドなどを実行することができます。サブプロセスの実行後は、ストリームまたはコールバックの形式で戻ります。

1. child_process モジュールによって提供される API

child_process は、新しい子プロセスを作成するための 4 つのメソッド、spawn、execFile、exec、fork を提供します。すべてのメソッドは非同期であり、図を使用してこれら 4 つのメソッドの違いを説明できます。

node.jsのchild_processモジュールとclusterモジュールの解析(コード例)

上の図は、これら 4 つの方法の違いを示すことができ、また、これら 4 つの方法の違いを簡単に紹介することもできます。

  • spawn: 一連のパラメーターが提供された後、非ノード プログラムが子プロセスで実行され、実行結果がストリームの形式で返されます。

  • execFile: 一連のパラメーターが提供された後、非ノード プログラムが子プロセスで実行され、実行結果がコールバックの形式で返されます。

  • exec: 子プロセスはシェルコマンドの文字列を渡して非ノードプログラムを実行し、実行後に結果がコールバックの形式で返されます。 execFile
    との違いは、exec が直接実行できることです。一連のシェルコマンドを実行します。

  • fork: 子プロセスは、一連のパラメーターを提供した後、実行結果をストリームの形式で返します。fork によって生成された子プロセスは、ノード アプリケーションのみを実行できます。次のセクションでは、これらの方法について詳しく紹介します。

2. execFile と exec

まず、これら 2 つのメソッドの違いを比較します。

は非ノード アプリケーションを実行し、実行結果はコールバック関数の形式で返されます。 。

違いは次のとおりです:

execは直接実行されるシェルコマンドですが、execFileは実行されるアプリケーションです

例えば、echoはUNIXシステムの組み込みコマンドです。コマンドラインで直接実行可能:

echo hello world

その結果、コマンドラインに hello world が出力されます。

(1) exec で実装

exec メソッドを使用したい場合は、新しい main.js ファイルを作成します。次に、このファイルに次のように記述します:

let cp=require('child_process');
cp.exec('echo hello world',function(err,stdout){
  console.log(stdout);
});

この main.js を実行すると、結果は hello world になります。 exec の最初のパラメータはシェル コマンドと完全に似ていることがわかりました。

(2) execFile による実装

let cp=require('child_process');
cp.execFile('echo',['hello','world'],function(err,stdout){
   console.log(stdout);
});

execFile は、echo という名前のアプリケーションを実行してパラメータを渡すのと似ています。 execFlie は、process.env.PATH のパス内で「echo」という名前のアプリケーションを検索し、見つかった後に実行します。デフォルトの process.env.PATH パスには「usr/local/bin」が含まれており、「echo」という名前のこのプログラムは「usr/local/bin」ディレクトリに存在し、実行後に hello と world の 2 つのパラメータを渡します。

(3) セキュリティ分析

exec と同様に、シェルを直接実行するのは非常に危険です。たとえば、次のようなシェルがあります:

echo hello world;rm -rf

exec を通じて直接実行でき、rm -rf は現在のディレクトリを削除します。書類。 exec はコマンドラインと同じで、実行レベルが非常に高く、実行後にセキュリティの問題が発生します。ただし、execFile は異なります。

execFile('echo',['hello','world',';rm -rf'])

パラメータを渡すときに、渡された実際のパラメータの実行のセキュリティが検出されます。セキュリティ上の問題がある場合、例外がスローされます。 execFile に加えて、spawn と fork はシェルを直接実行できないため、より安全です。

3. spawn

spawn は非ノードアプリケーションの実行にも使用され、シェルを直接実行できません。 execFile と比較して、アプリケーションの実行結果は実行完了後に一度だけ出力されるのではなく、ストリームで出力されます。 . 形式で出力します。大量のデータ出力の場合は、ストリームの形式でメモリの使用を導入できます。

例としてファイルの並べ替えと重複排除を使用します。

node.jsのchild_processモジュールとclusterモジュールの解析(コード例)

上の図の図では、最初に読み取られた input.txt ファイルには acba 未並べ替えのテキストが含まれており、並べ替えプログラム関数によって並べ替えることができます。出力は aabc で、最後に uniq プログラムを使用して重複を削除し、abc を取得できます。スポーン ストリームの入出力を使用して、上記の機能を実現できます。

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);

実行後、最終結果は process.stdout に入力されます。ファイル input.txt が大きい場合、ストリーム形式での入出力によりメモリ使用量を大幅に削減できます。バッファを設定すると、入出力効率を向上させながらメモリ使用量を削減できます。

4. フォーク

JavaScript では、大量の計算タスクを処理するという点で、HTML は Web 作業を通じて実装され、タスクがメインスレッドから分離されます。ノードでは親プロセスと子プロセス間の組み込み通信を使用してこの問題を処理し、ビッグデータ操作への負担を軽減します。ノードにはforkメソッドが用意されており、forkメソッドによりノードプログラムが別プロセスで実行され、親子間の通信により子プロセスが親プロセスの情報を受け取り、実行結果を親プロセスに返す。 。

fork メソッドを使用すると、親プロセスと子プロセスの間で IPC チャネルを開くことができ、異なるノード プロセス間のメッセージ通信が可能になります。

子プロセス内:

process.on('message') および process.send() のメカニズムを通じてメッセージを送受信します。

親プロセス内:

child.on('message') と process.send() のメカニズムを通じてメッセージを送受信します。

child.jsの具体例:

process.on('message',function(msg){
   process.send(msg)
})

parent.jsの場合:

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');

parent.jsを実行するとコマンドラインに出力されます: got a message is hello world

親と子の通信を中断する方法, 親プロセスで

child.disconnect()

を呼び出すことで、親と子間のIPC通信を切断できます。

5、同步执行的子进程

exec、execFile、spawn和fork执行的子进程都是默认异步的,子进程的运行不会阻塞主进程。除此之外,child_process模块同样也提供了execFileSync、spawnSync和execSync来实现同步的方式执行子进程。

三、node中的cluster模块

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中http模块和url模块简介

Node.js中关于多进程模块Cluster的详细介绍以及如何使用

以上がnode.jsのchild_processモジュールとclusterモジュールの解析(コード例)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。