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

推薦する

Macでのファイル権限の表示と設定の詳細な説明

序文Mac システムのターミナルでファイルの権限を変更するには、Linux の chmod コマンド...

Ubuntu は、Mysql+Keepalived の高可用性実装 (デュアルアクティブ ホットスタンバイ) を構築します。

Mysql5.5 デュアルマシン ホットスタンバイ実装 2つのMySQLをインストールするMySQ...

VMware15 の CentOS7 インストールの詳細なプロセスとよくある問題 (画像とテキスト)

1. インストールパッケージの準備VMware-player-15.0.4-12990004、非商...

初心者のためのWebページ作成: HTMLのハイパーリンクAタグの使い方を学ぶ

ハイパーリンク a タグはリンク ポイントを表し、英語の単語「anchor」の略語です。その機能は、...

Dockerコンテナでユーザーを切り替えるときに権限が不足する問題を解決する方法

Docker コンテナでユーザーを切り替えると、権限が不十分であるというメッセージが表示されます。解...

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

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

Oracle の開閉の 4 つのモード

>1 データベースを起動するcmd コマンド ウィンドウで、「sqlplus」を直接入力して ...

Linux ユーザー グループと権限の概要

ユーザーグループLinux では、すべてのユーザーはグループに属する必要があり、Linux には次の...

ナビゲーションバーのドロップダウンメニューのサンプルコードを実装するためのHTML+CSS

効果コード内の画像は自分で変更できますドロップダウンメニューのHTMLコード <ヘッダークラ​...

MySql 5.6.35 winx64 インストール詳細チュートリアル

注: データベースのバージョンの問題により、プロジェクトの起動時にエラーは発生しませんでしたが、デー...

純粋な CSS カスタム複数行省略記号の問題 (原理から実装まで)

テキストオーバーフローを表示するにはどうすればいいですか? どのようなニーズがありますか?単一行です...

Jmeterはデータベースプロセスダイアグラムに接続します

1. MySQL jdbc ドライバー (mysql-connector-java-5.1.28.j...

Vue で SVG アイコンを導入する 2 つの方法

Vue で SVG アイコンを導入する方法Vue で svg アイコンを導入する方法 1インストール...

Nginx_geo モジュールを使用して CDN スケジュールを設定する方法

NginxのGeoモジュールの紹介geo ディレクティブは、ngx_http_geo_module ...

NodeJS は画像テキスト分割を実現します

この記事では、画像テキストセグメンテーションを実装するためのNodeJSの具体的なコードを参考までに...