Node.jsで子プロセスを作成する方法

Node.jsで子プロセスを作成する方法

導入

Node.js のメイン イベント ループはシングル スレッドです。Node.js 自体も、時間のかかる操作を処理するためにワーカー プールを維持しています。また、Node.js が提供する worker_threads を使用して、手動で新しいスレッドを作成し、独自のタスクを実行することもできます。

この記事では、Node.js タスク、子プロセスを実行する新しい方法を紹介します。

子プロセス

lib/child_process.js は、子プロセスを作成できる child_process モジュールを提供します。

worker_threads は子スレッドを作成し、child_process は子プロセスを作成することに注意してください。

child_process モジュールでは、プロセスを同期的または非同期的に作成できます。同期作成方法は、非同期作成方法の後に Sync を追加するだけです。

作成されたプロセスは、ChildProcess クラスによって表されます。

ChildProcess の定義を見てみましょう。

インターフェイス ChildProcess は events.EventEmitter を拡張します {
 stdin: 書き込み可能 | null;
 stdout: 読み取り可能 | null;
 stderr: 読み取り可能 | null;
 読み取り専用チャネル?: パイプ | null;
 読み取り専用stdio: [
  書き込み可能 | null, // stdin
  読み取り可能 | null, // stdout
  読み取り可能 | null, // stderr
  読み取り可能 | 書き込み可能 | null | undefined、// 追加
  読み取り可能 | 書き込み可能 | null | undefined // 追加
 ];
 読み取り専用で削除されました: ブール値;
 読み取り専用 pid: 数値;
 読み取り専用接続: ブール値;
 読み取り専用終了コード: 数値 | null;
 読み取り専用シグナルコード: NodeJS.Signals | null;
 読み取り専用spawnargs: string[];
 読み取り専用の spawnfile: 文字列;
 kill(シグナル?: NodeJS.Signals | 数値): ブール値;
 send(message: Serializable、callback?: (error: Error | null) => void): boolean;
 send(message: Serializable、sendHandle?: SendHandle、callback?: (error: Error | null) => void): boolean;
 send(message: Serializable、sendHandle?: SendHandle、options?: MessageOptions、callback?: (error: Error | null) => void): boolean;
 切断(): 無効;
 参照を解除します。
 ref(): void;

 /**
  * イベント.EventEmitter
  * 1.閉じる
  * 2. 切断する
  * 3. エラー
  * 4. 終了
  * 5. メッセージ
  */
 ...
 }

ChildProcess も EventEmitter であるため、イベントを送受信できることがわかります。

ChildProcess は、close、disconnect、error、exit、message の 5 種類のイベントを受信できます。

切断イベントは、親プロセスで subprocess.disconnect() が呼び出されたとき、または子プロセスで process.disconnect() が呼び出されたときにトリガーされます。

プロセスを作成できない場合、プロセスを終了できない場合、または子プロセスにメッセージを送信できない場合に、エラー イベントがトリガーされます。

子プロセスが終了すると、終了イベントがトリガーされます。

子プロセスの stdio ストリームが閉じられると、close イベントが発行されます。 複数のプロセスが同じ stdio を共有する可能性があるため、close イベントは exit イベントとは異なることに注意してください。そのため、exit イベントを送信しても、必ずしも close イベントがトリガーされるわけではありません。

close と exit の例を見てみましょう。

const { spawn } = require('child_process');
ls = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('データ', (データ) => {
 console.log(`stdout: ${data}`);
});

ls.on('close', (コード) => {
 console.log(`子プロセスはコード $[code] を使用してすべての stdio を閉じます`);
});

ls.on('exit', (コード) => {
 console.log(`子プロセスはコード $[code] で終了しました`);
});

最後に、子プロセスが process.send() を使用してメッセージを送信したときにトリガーされるメッセージ イベントがあります。

ChildProcess には、stderr、stdout、stdin、stdio といったいくつかの標準ストリーム属性があります。

stderr、stdout、stdin は簡単に理解できます。それぞれ標準エラー、標準出力、標準入力です。

stdout の使用法を見てみましょう。

const { spawn } = require('child_process');

const サブプロセス = spawn('ls');

サブプロセス.stdout.on('データ', (データ) => {
 console.log(`データブロック ${data} を受信しました`);
});

stdio は実際には stderr、stdout、stdin の集合です。

読み取り専用stdio: [
  書き込み可能 | null, // stdin
  読み取り可能 | null, // stdout
  読み取り可能 | null, // stderr
  読み取り可能 | 書き込み可能 | null | undefined、// 追加
  読み取り可能 | 書き込み可能 | null | undefined // 追加
 ];

このうち、stdio[0]はstdin、stdio[1]はstdout、stdio[2]はstderrを表します。

子プロセスが stdio で作成されるときに 3 つの標準ストリームがパイプ以外に設定されている場合、stdin、stdout、および stderr は null になります。

stdio を使用した例を見てみましょう。

const assert = require('assert');
定数 fs = require('fs');
定数 child_process = require('child_process');

定数サブプロセス = child_process.spawn('ls', {
 標準入出力:
 0, // 子プロセスに親プロセスの標準入力を使用します。
 'pipe', // 子プロセスの stdout をパイプ経由で親プロセスに渡します。
 fs.openSync('err.out', 'w') // 子プロセスの stderr をファイルに送信します。
 ]
});

assert.strictEqual(サブプロセス.stdio[0]、null);
assert.strictEqual(サブプロセス.stdio[0]、サブプロセス.stdin);

サブプロセス.stdout をアサートします。
assert.strictEqual(サブプロセス.stdio[1]、サブプロセス.stdout);

assert.strictEqual(サブプロセス.stdio[2]、null);
assert.strictEqual(サブプロセス.stdio[2]、サブプロセス.stderr);

通常、親プロセスは子プロセスへの参照カウントを維持し、子プロセスが終了した後にのみ親プロセスが終了します。

この参照は ref であり、unref メソッドが呼び出されると、親プロセスは子プロセスとは独立して終了できるようになります。

const { spawn } = require('child_process');

const サブプロセス = spawn(process.argv[0], ['child_program.js'], {
 分離: true、
 stdio: '無視'
});

サブプロセス.unref();

最後に、ChildProcess を通じてメッセージを送信する方法を見てみましょう。

サブプロセス.send(メッセージ[, sendHandle[, オプション]][, コールバック])

ここで、message は送信されるメッセージであり、callback はメッセージが送信された後のコールバックです。

sendHandle は特別です。TCP サーバーまたはソケット オブジェクトにすることができ、これらのハンドルを子プロセスに渡します。子プロセスは、メッセージ イベント内のコールバック関数にハンドルを渡し、子プロセスで処理できるようにします。

TCP サーバーを通過する例を見てみましょう。まず、メイン プロセスを見てみましょう。

サブプロセスは、'child_process' を要求します。'subprocess.js' をフォークします。

// サーバー オブジェクトを開き、ハンドルを送信します。
const server = require('net').createServer();
server.on('接続', (ソケット) => {
 socket.end('親プロセスによって処理されます');
});
server.listen(1337, () => {
 サブプロセス.send('server', server);
});

サブプロセスをもう一度見てみましょう。

process.on('メッセージ', (m, server) => {
 if (m === 'サーバー') {
 server.on('接続', (ソケット) => {
 socket.end('子プロセスによって処理されました');
 });
 }
});

子プロセスがサーバー ハンドルを受信し、子プロセスで接続イベントをリッスンしていることがわかります。

ソケット オブジェクトを渡す例を見てみましょう。

onst { fork } = require('child_process');
'subprocess.js' を fork します。
'subprocess.js' を fork します。

// サーバーを起動し、ソケットを子プロセスに送信します。
// 子プロセスに送信される前にソケットが読み取られないようにするには、`pauseOnConnect` を使用します。
const server = require('net').createServer({ pauseOnConnect: true });
server.on('接続', (ソケット) => {

 // 特別な優先度。
 (ソケット.リモートアドレス === '74.125.127.100')の場合{
 special.send('socket', ソケット);
 戻る;
 }
 // 通常の優先度。
 通常は、ソケットを送信します。
});
サーバーを listen (1337);

subprocess.js の内容:

process.on('メッセージ', (m, ソケット) => {
 if (m === 'ソケット') {
 if (ソケット) {
 // クライアントソケットが存在するかどうかを確認します。
 // ソケットは、送信されてから子プロセスによって受信されるまでの間に閉じられることがあります。
 socket.end(`リクエストは${process.argv[2]}の優先度を使用して処理されます`);
 }
 }
});

メイン プロセスは、特別な優先度のサブプロセスと通常の優先度のサブプロセスの 2 つを作成します。

プロセスを非同期的に作成する

child_process モジュールには、プロセスを非同期に作成する 4 つの方法、つまり、child_process.spawn()、child_process.fork()、child_process.exec()、child_process.execFile() があります。

まず、各メソッドの定義を見てみましょう。

child_process.spawn(コマンド[, 引数][, オプション])

child_process.fork(モジュールパス[, 引数][, オプション])

child_process.exec(コマンド[, オプション][, コールバック])

child_process.execFile(ファイル[, 引数][, オプション][, コールバック])

このうち、child_process.spawn が基礎となり、非同期的に新しいプロセスを生成します。その他の fork、exec、execFile はすべて spawn をベースに生成されます。

Fork により新しい Node.js プロセスが生成されます。

exec と execFile は、コールバックを使用して新しいプロセスで新しいコマンドを実行します。それらの違いは、Windows 環境では、.bat ファイルまたは .cmd ファイルを実行する場合、シェル ターミナルがないと実行できないことです。現時点では、exec でのみ起動できます。 execFile は実行可能ではありません。

あるいは、spawn を使用することもできます。

Windows で spawn と exec を使用する例を見てみましょう。

// Windows のみ。
const { spawn } = require('child_process');
const bat = spawn('cmd.exe', ['/c', 'my.bat']);

bat.stdout.on('データ', (データ) => {
 コンソールにログ出力します。
});

bat.stderr.on('データ', (データ) => {
 コンソールエラー(data.toString());
});

bat.on('exit', (コード) => {
 console.log(`サブプロセスが終了しました。終了コードは $[code]`);
});
const { exec, spawn } = require('child_process');
exec('my.bat', (err, stdout, stderr) => {
 もし(エラー){
 コンソールエラー(err);
 戻る;
 }
 コンソールログ(標準出力)
});

// ファイル名にスペースが含まれるスクリプト:
const bat = spawn('"my script.cmd"', ['a', 'b'], { shell: true });
// または:
exec('"my script.cmd" a b', (err, stdout, stderr) => {
 // ...
});

同期作成プロセス

プロセスを同期的に作成するには、child_process.spawnSync()、child_process.execSync()、および child_process.execFileSync() を使用できます。同期メソッドは、Node.js イベント ループをブロックし、子プロセスが終了するまで他のコードの実行を中断します。

通常、一部のスクリプト タスクでは、同期作成プロセスを使用するのが一般的です。

これで、Node.js で子プロセスを作成する方法についての記事は終了です。Node.js で子プロセスを作成する方法の詳細については、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Nodejs エラー処理プロセス記録
  • Node.js環境でMySQLデータベースを素早く操作する方法を詳しく説明します
  • Nodejs でタイムドクローラーを実装する完全な例
  • NodeJSとブラウザにおけるこのキーワードの違い
  • Node.js の TCP 接続処理のコア プロセス
  • Nodejs 配列キューと forEach アプリケーションの詳細な説明
  • 1 つの記事で Node.js の非同期プログラミングを学ぶ
  • nodejs で worker_threads を使用して新しいスレッドを作成する方法
  • Nodejs での WeChat アプレット メッセージ プッシュの実装
  • Nodejs で WeChat アカウント分割を実装するためのサンプルコード
  • Node.js における非同期プログラミングの知識ポイントの詳細な説明
  • nodejs+expressでデータベースに接続する最も簡単な方法
  • Windows でインストールされた Node.js の上位バージョンを下位バージョンにダウングレードする方法 (グラフィック チュートリアル)
  • NodeJS CORS設定の実装プロセスの詳細な説明
  • Node.js を使用して定期的にメールリマインダーを自動的に送信する方法 (非常に実用的)
  • Alibaba Cloud での Node.js プロジェクトの簡単なデプロイ
  • Node.js を使用してコマンドライン ゲームを実装する方法
  • Node.jsを理解するのはとても簡単です

<<:  Ubuntu 上の MySQL における中国語文字化け問題の解決方法

>>:  実行後にdocker nginxにアクセスできない問題の解決策

推薦する

MySQL エラー: 接続数が多すぎる場合の解決策

MySQLデータベースの接続が多すぎますこのエラーは明らかに、mysql_connect の後に m...

Git サーバーを使用してデバッグ ブランチを表示し、修正する方法を 1 日 1 分で学習します。

デバッグブランチプロジェクトの通常の開発中に、以前にリリースされたバージョンにバグがある場合がありま...

VueのVuexの4つの補助機能について

目次1. 補助機能2. 例1. mapState と mapGetters 2. mapMutati...

スライダー検証コードを実装するJavaScript

この記事では、スライダー検証コードを実装するためのJavaScriptの具体的なコードを参考までに共...

JS配列メソッドsome、every、findの使用に関する詳細

目次1. いくつか2. すべての3. 見つける1. いくつかsome()メソッドは、指定された関数の...

Dockerコンテナが外部ネットワークにpingできない問題を解決する

今日、docker で redis 環境を構築していたところ、yum がリソースを取得できず、インタ...

Vue3はフロントエンドのログを出力するためにaxiosインターセプターを使用する

目次1. はじめに2. axiosインターセプターを使用してフロントエンドログを出力する1. はじめ...

CocosCreator でレイヤー管理に常駐ノードを使用する方法

CocosCreator バージョン: 2.3.4ほとんどのゲームにはレイヤー管理機能があり、例えば...

MySQL テーブルスペースとは何ですか?

今日皆さんにお伝えしたいトピックは、「皆さんがよく話題にするテーブル スペースとは一体何でしょうか。...

CSS3を使用して背景画像の色を変更するさまざまな方法

CSS3 では画像の色を変更できます。これからは複数の絵をデザインする必要がなくなり、いつでも修正で...

MySQL DEFINER の使用方法の詳細な説明

目次序文: 1.DEFINERの簡単な紹介2. いくつかの注意点要約:序文: MySQL データベー...

グリーンスタイルのウェブデザイン作品18点の最新コレクション

トイ・ストーリー3 オンラインマーケティングウェブサイトゼンモバイル鉄から鉄へスプラウトファンドバー...

Vueはローカルストレージの追加、削除、変更機能を実装します

この記事では、ローカルストレージの追加、削除、変更を実装するためのVueの具体的なコードを例として紹...

異なるインデックスを更新してMySQLのデッドロックルーチンを解決する

前回の記事では、ソース コードを使用してロック関連の情報をデバッグする方法を紹介しました。ここでは、...

CSS3 border-radius 丸角の実装方法と使い方の詳しい説明

以前は、角を丸くするのは非常に面倒でしたが、CSS3 では、角を丸くするのは非常に簡単になり、bor...