序文
child_processを理解する前に、まず、いくつかのコンピューター オペレーティング システムの基本概念とそれらの間の関係を理解しましょう。
- カップ: コンピューターには、5 つの基本的なハードウェア演算装置、コントローラー、メモリー、入力、および出力デバイスが含まれています。演算装置とコントローラは、中央処理装置である CPU (Central Processing Unit) に統合されています。CPU の主な機能は、一連の命令演算を実行し、結果を書き戻すことです。
- プロセス:プロセスは、システムによるリソースの割り当てとスケジューリングの基本単位です.一度に 1 つの CPU で実行できるプロセスは 1 つだけであり、独立したメモリを占有します. しかし、コンピュータが実行されているときは、複数のプロセスが実行されているに違いないと考えるかもしれません。最新のオペレーティング システムでは、すべてのプロセスが順番に CPU を使用しますが、CPU は非常に効率的であるため、複数のタスクをすばやく切り替えることができ、複数のタスクが同時に実行されているように感じられます。
- スレッド:スレッドはプロセス内のエンティティです. プロセスは複数のスレッドを持つことができ, スレッドには親プロセスが必要です. スレッドはシステム リソースを所有せず、スレッドはプロセスが所有するすべてのリソースを共有しますが、スレッドの 1 つが共有メモリの一部を使用する場合、他のスレッドはこのメモリの一部を使用する前にそれが終了するのを待つ必要があります。
ノードが単一のスレッドで実行されることはわかっています. node app.js を使用してノード サービスを開始すると、サーバー上でノード プロセスが実行され、js コードはいずれかのスレッドでのみ実行されます. ノードの設計では、時間のかかる操作をオペレーティング システムまたは他のスレッドに委任します. これらの操作は、I/O
ディスク I/O やネットワークなどの一般的な非同期操作であり、これらの時間のかかる操作をメイン スレッドから分離します. ノードは言語レベルからのスレッドの作成をサポートしていませんが、child_process モジュールを使用して新しいプロセスを作成し、シェル スクリプトを実行して大きなファイルをアップロードまたはダウンロードするなど、時間とリソースを消費する操作を完了してから、実行結果がメイン スレッドに
この記事では、主にNode.js のchild_processモジュールの関連内容を紹介します. child_processモジュールを紹介する前に、例を見てみましょう.
const http = require('http');
const longComputation = () => {
let sum = 0;
for (let i = 0; i < 1e10; i++) {
sum += i;
};
return sum;
};
const server = http.createServer();
server.on('request', (req, res) => {
if (req.url === '/compute') {
const sum = longComputation();
return res.end(`Sum is ${
sum}`);
} else {
res.end('Ok')
}
});
server.listen(3000);
You can try to use the above code to start the Node.js service, and then open two browser tabs to visit /compute and / それぞれ. ノード サービスが /compute リクエストを受信すると、多数の処理が実行されることがわかります。他のask(/)に応答しなくなる原因となります。
Java言語では上記の問題をマルチスレッド化することで解決できますが、Node.jsはコード実行時にシングルスレッド化するため、Node.jsは上記の問題をどのように解決すればよいのでしょうか。実際、Node.js は子プロセスを作成して、集中的な CPU コンピューティング タスク (上記の例の longComputation など) を実行し、問題を解決することができ、child_process モジュールを使用して子プロセスを作成します。
child_process は、子プロセスを作成するいくつかの方法を提供します
- 非同期モード:
spawn
、exec
、execFile
、fork
- 同期方法:
spawnSync
、execSync
、execFileSync
エグゼクティブ
文法:child_process.exec(command[, options][, callback])
ここでの最初のパラメーター command は、シェルで実行されるコマンドです。オプションは、cwd (現在の作業ディレクトリ)、shell (コマンドを実行するシェル)、uid、gid、encoding などの実行コマンドに関連するパラメーターを設定できます。 .; callback コマンドが実行されて呼び出された後、コールバック関数の stdout を介してコマンド出力を取得できます。options と callback はオプションのパラメーターです。たとえば、/Usrs/ben ディレクトリで「ls -l」を実行する場合、コードは次のようになります。
const {
exec } = require('child_process');
exec('ls -l',{
cwd: '/Users/liu/Desktop'}, (error, stdout, stderr) => {
if (error) return;
console.log('stdout:', stdout);
})
// stdout: total 4792
// -rw-r--r--@ 1 liuchongyang staff 53248 May 24 2022 10起诉状(一审).doc
// -rw-r--r--@ 1 liuchongyang staff 34816 May 24 2022 11答辩状(一审).doc
// -rw-r--r--@ 1 liuchongyang staff 33280 May 24 2022 12质证意见(一审).doc
// -rw-r--r--@ 1 liuchongyang staff 65024 May 24 2022 13代理词(一审营).doc
実行ファイル
文法:child_process.execFile(file[, args][, options][, callback])
execFile は、名前が示すように、実行可能ファイルを実行します。通常、Unix タイプのオペレーティング システムでは、execFile はシェルを生成しないため、exec よりも効率的です。Windows システムでは、 .bat
and.cmd
ファイルはターミナルがないと単独では実行できないため、execFile を使用して実行することはできませんが、exec または後述の spawn を使用して実行する必要があります。
execFile メソッドの file パラメーターは必須で、実行するファイルを指定します。args はオプションで、実行ファイルに渡されるパラメーターのリストです。オプションとコールバックは exec のものと同様なので、ここでは説明しません。詳細。次に、ノードのバージョンを確認します。コードは次のようになります。
const {
execFile } = require('child_process');
execFile('/usr/local/bin/node', ['-v'], (error, stdout, stderr) => {
if (error) return;
console.log('stdout:', stdout);
})
// stdout: v12.17.0
スポーン
文法:child_process.spawn(command[, args][, options])
spawn
機能と同様にexec
、コマンドを実行しますが、spawn はコールバック関数の形式で stdout を受け取りませんが、子プロセス オブジェクトの stdout でデータ イベントをリッスンして標準出力データを取得します。このように、stdout はストリームの形式で送信されます。これは、出力の終了後にコールバックを呼び出す exec の方法よりもはるかに効率的です。
exec に示されている例を使用して、/Usrs/ben ディレクトリで「ls -l」を実行すると、コードは次のようになります。
const {
spawn } = require('child_process');
const subprocess = spawn('ls', ['-l'], {
cwd: '/Users/ben'});
subprocess.stdout.on('data', (data) => {
console.log(data.toString());
});
// total 8
// drwx------@ 7 ben staff 224 7 28 09:36 Applications
// drwx------@ 25 ben staff 800 7 31 22:19 Desktop
// drwx------@ 24 ben staff 768 6 21 17:18 Documents
// drwx------@ 79 ben staff 2528 7 31 20:25 Downloads
// ...
フォーク
文法:child_process.fork(modulePath[, args][, options])
fork() の最初のパラメーターがノード モジュール パスであるため、fork は実際には spawn の特殊なケースです。args および options パラメータは spawn と同じです。ただし、fork はノード モジュールを実行するため、fork は機能を提供します。つまり、IPC チャネルが親プロセスと子プロセスの間に確立され、親プロセスと子プロセスが send() メソッドを介して相互に情報を送信できるようになります。例えば:
child.js
//child.js
process.on('message',function(msg){
console.log('child receive msg:', msg) // child receive msg: hello world
process.send(msg)
})
親.js
// parent.js
let cp=require('child_process');
let child=cp.fork('./child');
child.on('message',function(msg){
console.log('parent get messg:',msg); // parent get messg: hello world
});
child.send('hello world');
fork は親プロセスと子プロセス間の通信チャネルを確立するため、同期 fork がある場合、この IPC チャネルは存在しないため、fork に対応する同期メソッドはありません。
要約する
子プロセスを作成する 4 つの方法の中で、spawn と fork は比較的よく使用されます.Spawn はオペレーティング システム コマンドを処理します.fork はノード モジュールを処理します (そして通信のために親プロセスと子プロセスの間に IPC チャネルが確立されます).exec はシェルを直接使用しますシェルでパイプラインなどの機能を利用するが、出力結果はコールバックで一度出力されるため、特に出力データが大きい場合には不向き、execFileは不向きWindows システム用。