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にアクセスできない問題の解決策

推薦する

HTML 中国語文字エンコード標準の概要

HTML では、Web ページで使用されるエンコーディングを指定する必要があります。一般的な指定方法...

MySQL でのトランザクションの使用方法

基礎トランザクションは、SQL ステートメントのグループに対するアトミック操作です。つまり、グループ...

Docker を使用した SQL Server の実行の実装

現在、.net Core はクロスプラットフォームであり、誰もが Linux と Docker を使...

html 内の絶対パス URL と相対パス URL、サブディレクトリ、親ディレクトリ、ルート ディレクトリ

絶対 URL は、インターネット上の特定のファイルに必要なすべてのコンテンツを表すために使用されます...

Webフロントエンドインターフェースの設計に必須のスキル

[必須] ユーザーインターフェースPhotoShop/花火デザインアーティストと協力して、スケッチを...

MySQL の結合テーブルにインデックスを作成する方法

この記事では、MySQL で 2 つのテーブルを関連付ける結合テーブルにインデックスを作成する方法を...

Docker を使用して MySQL 5.7 および 8.0 マスター スレーブ クラスターをデプロイする方法

> MySQL 5.7 クラスタ マスターとスレーブをデプロイする (テストのみ)イメージバー...

mysql ERROR 1045 (28000) 問題の解決方法

私はmysql ERROR 1045に遭遇し、この問題に長い時間を費やしました。私はそれを自分で書き...

Linux で PHP curl 拡張機能をインストールする方法の詳細な説明

この記事では、Linux で PHP curl 拡張機能をインストールする方法について説明します。ご...

MySQL マルチテーブル結合クエリの詳細な説明

目次複数テーブル結合クエリ内部結合左結合右結合サブクエリ要約する複数テーブル結合クエリテーブル間の接...

CSSとHTMLを組み合わせる4つの方法

(1)各HTMLタグには属性スタイルがあり、CSSとHTMLを組み合わせている。 <div s...

Centos7にnginxをインストールする方法

必要な環境をインストールする1. gccのインストールnginx をインストールするには、公式サイト...

jQueryはマウスドラッグ画像機能を実装します

この例では、jQuery を使用してマウス ドラッグ イメージ機能を実装します。まず、ラッパーを設定...

Vueリストデータを削除した後、ページを自動的に更新する方法と更新方法の詳細な説明

問題の説明:フロントエンドがデータの一部を削除したり、新しいデータを追加したりすると、バックエンドの...

更新とデータ整合性処理のためのMySQLトランザクション選択の説明

MySQL のトランザクションはデフォルトで自動的にコミットされます (autocommit = 1...