Node.jsで子プロセスを起動する方法
序章
ユーザーが単一のNode.jsプログラムを実行すると、実行中のプログラムのインスタンスを表す単一のオペレーティングシステム(OS)processとして実行されます。 そのプロセス内で、Node.jsは単一のスレッドでプログラムを実行します。 このシリーズの前半でNode.jsチュートリアルで非同期コードを作成する方法で説明したように、1つのプロセスで実行できるスレッドは1つだけであるため、JavaScriptで実行するのに長い時間がかかる操作] Node.jsスレッドをブロックし、他のコードの実行を遅らせることができます。 この問題を回避するための重要な戦略は、子プロセス、または実行時間の長いタスクに直面したときに別のプロセスによって作成されたプロセスを起動することです。 新しいプロセスが起動されると、オペレーティングシステムはマルチプロセッシング技術を使用して、メインのNode.jsプロセスと追加の子プロセスが同時に実行されるようにすることができます。
Node.jsには、新しいプロセスを作成する関数を持つ child_processmoduleが含まれています。 このモジュールは、長時間実行されるタスクを処理するだけでなく、OSとインターフェイスして、shellコマンドを実行することもできます。 システム管理者は、Node.jsを使用してシェルコマンドを実行し、シェルスクリプトではなくNode.jsモジュールとして操作を構造化および維持できます。
このチュートリアルでは、一連のサンプルNode.jsアプリケーションを実行しながら子プロセスを作成します。 を使用してプロセスを作成します child_process
モジュールは、 bufferまたはexec()関数を使用した文字列を介して、次に spawn()関数を使用してデータストリームから子プロセスの結果を取得します。 ]。 最後に、 fork()を使用して、実行中に通信できる別のNode.jsプログラムの子プロセスを作成します。 これらの概念を説明するために、ディレクトリの内容を一覧表示するプログラム、ファイルを検索するプログラム、および複数のエンドポイントを持つWebサーバーを作成します。
前提条件
-
これらの例を実行するには、Node.jsがインストールされている必要があります。 このチュートリアルでは、バージョン10.22.0を使用します。 これをmacOSまたはUbuntu18.04にインストールするには、Node.jsをインストールしてmacOSにローカル開発環境を作成する方法またはの
PPAを使用したインストール ]セクションの手順に従います。 Ubuntu18.04にNode.jsをインストールする方法。 -
この記事では、Webサーバーを作成する例を使用して、
fork()
機能が動作します。 Webサーバーの作成に慣れるために、HTTPモジュールを使用してNode.jsでWebサーバーを作成する方法に関するガイドを読むことができます。
ステップ1—で子プロセスを作成する exec()
開発者は通常、シェルのパイピングやリダイレクトを使用するなど、シェルを使用してNode.jsプログラムの出力を操作する必要がある場合に、オペレーティングシステムでコマンドを実行する子プロセスを作成します。 The exec()
Node.jsの関数は、新しいシェルプロセスを作成し、そのシェルでコマンドを実行します。 コマンドの出力はメモリ内のバッファに保持され、コールバック関数に渡されて受け入れることができます。 exec()
.
Node.jsで最初の子プロセスの作成を始めましょう。 まず、このチュートリアル全体で作成するスクリプトを保存するためのコーディング環境を設定する必要があります。 ターミナルで、というフォルダを作成します child-processes
:
- mkdir child-processes
ターミナルにそのフォルダを入力します cd
指図:
- cd child-processes
と呼ばれる新しいファイルを作成します listFiles.js
ファイルをテキストエディタで開きます。 このチュートリアルでは、ターミナルテキストエディタであるnanoを使用します。
- nano listFiles.js
を使用するNode.jsモジュールを作成します exec()
を実行する関数 ls
指図。 The ls
コマンドは、ディレクトリ内のファイルとフォルダを一覧表示します。 このプログラムは、 ls
コマンドを実行し、ユーザーに表示します。
テキストエディタで、次のコードを追加します。
const { exec } = require('child_process');
exec('ls -lh', (error, stdout, stderr) => {
if (error) {
console.error(`error: ${error.message}`);
return;
}
if (stderr) {
console.error(`stderr: ${stderr}`);
return;
}
console.log(`stdout:\n${stdout}`);
});
最初にインポートします exec()
からのコマンド child_process
JavaScriptデストラクチャリングを使用するモジュール。 インポートしたら、 exec()
関数。 最初の引数は、実行したいコマンドです。 この場合、それは ls -lh
、現在のディレクトリ内のすべてのファイルとフォルダを長い形式で一覧表示します。出力の上部には、人間が読める形式の合計ファイルサイズが表示されます。
2番目の引数は、次の3つのパラメーターを持つコールバック関数です。 error
, stdout
、 と stderr
. コマンドの実行に失敗した場合は、 error
失敗した理由をキャプチャします。 これは、実行しようとしているコマンドがシェルで見つからない場合に発生する可能性があります。 コマンドが正常に実行されると、コマンドが標準出力ストリームに書き込むすべてのデータがキャプチャされます。 stdout
、および標準エラーストリームに書き込むデータはすべてでキャプチャされます stderr
.
注:の違いを維持することが重要です error
と stderr
念頭に置いて。 コマンド自体の実行に失敗した場合は、 error
エラーをキャプチャします。 コマンドが実行されても出力がエラーストリームに返される場合は、 stderr
それをキャプチャします。 最も回復力のあるNode.jsプログラムは、子プロセスのすべての可能な出力を処理します。
コールバック関数では、最初にエラーを受け取ったかどうかを確認します。 行った場合は、エラーを表示します message
(のプロパティ Error
オブジェクト)と console.error()
そして関数をで終了します return
. 次に、コマンドがエラーメッセージを出力したかどうかを確認し、 return
もしそうなら。 コマンドが正常に実行されると、その出力をconsoleに記録します。 console.log()
.
このファイルを実行して、実際の動作を確認してみましょう。 まず、保存して終了します nano
を押すことによって CTRL+X
.
ターミナルに戻り、アプリケーションを実行します。 node
指図:
- node listFiles.js
端末に次の出力が表示されます。
Outputstdout:
total 4.0K
-rw-rw-r-- 1 sammy sammy 280 Jul 27 16:35 listFiles.js
これは、の内容を一覧表示します child-processes
長い形式のディレクトリと、上部のコンテンツのサイズ。 結果には、代わりに独自のユーザーとグループが含まれます sammy
. これは、 listFiles.js
プログラムはシェルコマンドを正常に実行しました ls -lh
.
次に、並行プロセスを実行する別の方法を見てみましょう。 Node.jsの child_process
モジュールは、実行可能ファイルを実行することもできます execFile()
関数。 との主な違い execFile()
と exec()
関数は、の最初の引数が execFile()
コマンドではなく実行可能ファイルへのパスになりました。 実行可能ファイルの出力は、次のようなバッファに保存されます。 exec()
、コールバック関数を介してアクセスします error
, stdout
、 と stderr
パラメーター。
注:Windowsのスクリプトなど .bat
と .cmd
ファイルはで実行できません execFile()
これは、ファイルの実行時に関数がシェルを作成しないためです。 Unix、Linux、およびmacOSでは、実行可能スクリプトを実行するために必ずしもシェルが必要なわけではありません。 ただし、Windowsマシンには、スクリプトを実行するためのシェルが必要です。 Windowsでスクリプトファイルを実行するには、 exec()
、新しいシェルを作成するため。 または、 spawn()
、このステップの後半で使用します。
ただし、実行できることに注意してください .exe
Windowsで正常に使用しているファイル execFile()
. この制限は、実行にシェルを必要とするスクリプトファイルにのみ適用されます。
の実行可能スクリプトを追加することから始めましょう execFile()
走る。 Node.jsWebサイトからNode.jsロゴをダウンロードするbashスクリプトを記述し、Base64がそれをエンコードしてデータを次の文字列に変換します。 ASCII文字。
と呼ばれる新しいシェルスクリプトファイルを作成します processNodejsImage.sh
:
- nano processNodejsImage.sh
次に、画像をダウンロードしてbase64で変換するスクリプトを記述します。
#!/bin/bash
curl -s https://nodejs.org/static/images/logos/nodejs-new-pantone-black.svg > nodejs-logo.svg
base64 nodejs-logo.svg
最初のステートメントはshebangステートメントです。 これは、Unix、Linux、およびmacOSで、スクリプトを実行するためのシェルを指定する場合に使用されます。 2番目のステートメントは curl
指図。 cURLユーティリティ、そのコマンドは curl
は、サーバーとの間でデータを転送できるコマンドラインツールです。 cURLを使用してWebサイトからNode.jsロゴをダウンロードし、リダイレクトを使用してダウンロードしたデータを新しいファイルに保存します nodejs-logo.svg
. 最後のステートメントは base64
をエンコードするユーティリティ nodejs-logo.svg
cURLでダウンロードしたファイル。 次に、スクリプトはエンコードされた文字列をコンソールに出力します。
続行する前に保存して終了します。
Nodeプログラムでbashスクリプトを実行するには、スクリプトを実行可能にする必要があります。 これを行うには、次を実行します。
- chmod u+x processNodejsImage.sh
これにより、現在のユーザーにファイルを実行する権限が与えられます。
スクリプトを配置したら、それを実行するための新しいNode.jsモジュールを作成できます。 このスクリプトは execFile()
子プロセスでスクリプトを実行し、エラーをキャッチしてすべての出力をコンソールに表示します。
ターミナルで、という新しいJavaScriptファイルを作成します getNodejsImage.js
:
- nano getNodejsImage.js
テキストエディタに次のコードを入力します。
const { execFile } = require('child_process');
execFile(__dirname + '/processNodejsImage.sh', (error, stdout, stderr) => {
if (error) {
console.error(`error: ${error.message}`);
return;
}
if (stderr) {
console.error(`stderr: ${stderr}`);
return;
}
console.log(`stdout:\n${stdout}`);
});
JavaScriptのdestructuringを使用してインポートします execFile()
からの機能 child_process
モジュール。 次に、その関数を使用して、ファイルパスを名として渡します。 __dirname
それが書かれているモジュールのディレクトリパスが含まれています。 Node.jsは __dirname
モジュールの実行時にモジュールへの変数。 を使用して __dirname
、スクリプトは常に processNodejsImage.sh
どこで実行しても、さまざまなオペレーティングシステム間でファイルを作成できます getNodejsImage.js
. 現在のプロジェクト設定では、 getNodejsImage.js
と processNodejsImage.sh
同じフォルダにある必要があります。
2番目の引数は、 error
, stdout
、 と stderr
パラメーター。 使用した前の例と同様に exec()
、スクリプトファイルの可能な出力をそれぞれチェックし、コンソールに記録します。
テキストエディタで、このファイルを保存してエディタを終了します。
ターミナルで、 node
モジュールを実行するには:
- node getNodejsImage.js
このスクリプトを実行すると、次のような出力が生成されます。
Outputstdout:
PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgNDQyLjQgMjcwLjkiPjxkZWZzPjxsaW5lYXJHcmFkaWVudCBpZD0iYiIgeDE9IjE4MC43IiB5MT0iODAuNyIge
...
サイズが大きいため、この記事では出力を切り捨てたことに注意してください。
画像をbase64でエンコードする前に、 processNodejsImage.sh
最初にそれをダウンロードします。 現在のディレクトリを調べて、イメージをダウンロードしたことを確認することもできます。
実行する listFiles.js
ディレクトリ内の更新されたファイルのリストを見つけるには:
- node listFiles.js
スクリプトは、ターミナルに次のようなコンテンツを表示します。
Outputstdout:
total 20K
-rw-rw-r-- 1 sammy sammy 316 Jul 27 17:56 getNodejsImage.js
-rw-rw-r-- 1 sammy sammy 280 Jul 27 16:35 listFiles.js
-rw-rw-r-- 1 sammy sammy 5.4K Jul 27 18:01 nodejs-logo.svg
-rwxrw-r-- 1 sammy sammy 129 Jul 27 17:56 processNodejsImage.sh
これで正常に実行されました processNodejsImage.sh
Node.jsの子プロセスとして execFile()
関数。
The exec()
と execFile()
関数は、Node.js子プロセスのオペレーティングシステムのシェルでコマンドを実行できます。 Node.jsは、同様の機能を備えた別のメソッドも提供します。 spawn()
. 違いは、シェルコマンドの出力を一度に取得するのではなく、ストリームを介してチャンクで取得することです。 次のセクションでは、 spawn()
子プロセスを作成するコマンド。
ステップ2—で子プロセスを作成する spawn()
The spawn()
関数は、プロセスでコマンドを実行します。 この関数は、ストリームAPIを介してデータを返します。 したがって、子プロセスの出力を取得するには、ストリームイベントをリッスンする必要があります。
Node.jsのストリームは、イベントエミッターのインスタンスです。 イベントのリッスンとストリームとの対話の基礎について詳しく知りたい場合は、Node.jsでのイベントエミッターの使用に関するガイドをお読みください。
多くの場合、選択することをお勧めします spawn()
以上 exec()
また execFile()
実行したいコマンドが大量のデータを出力できる場合。 によって使用されるバッファ付き exec()
と execFile()
、処理されたすべてのデータはコンピュータのメモリに保存されます。 大量のデータの場合、これによりシステムパフォーマンスが低下する可能性があります。 ストリームを使用すると、データは小さなチャンクで処理および転送されます。 したがって、一度に多くのメモリを使用することなく、大量のデータを処理できます。
使い方を見てみましょう spawn()
子プロセスを作成します。 子プロセスを作成して実行する新しいNode.jsモジュールを作成します find
指図。 を使用します find
現在のディレクトリ内のすべてのファイルを一覧表示するコマンド。
と呼ばれる新しいファイルを作成します findFiles.js
:
- nano findFiles.js
テキストエディタで、まず spawn()
指図:
const { spawn } = require('child_process');
const child = spawn('find', ['.']);
最初にインポートしました spawn()
からの機能 child_process
モジュール。 その後、 spawn()
を実行する子プロセスを作成する関数 find
指図。 プロセスへの参照は、 child
変数。ストリーミングされたイベントをリッスンするために使用します。
の最初の引数 spawn()
実行するコマンドです。この場合は find
. 2番目の引数は、実行されたコマンドの引数を含むarrayです。 この場合、Node.jsに実行するように指示しています find
引数付きのコマンド .
、これにより、コマンドが現在のディレクトリ内のすべてのファイルを検索するようにします。 ターミナルでの同等のコマンドは find .
.
とともに exec()
と execFile()
関数では、引数とコマンドを1つの文字列で記述しました。 しかし、 spawn()
、コマンドへのすべての引数は配列に入力する必要があります。 それは spawn()
、 ようではない exec()
と execFile()
、プロセスを実行する前に新しいシェルを作成しません。 引数を1つの文字列にまとめたコマンドを使用するには、Node.jsで新しいシェルも作成する必要があります。
コマンドの出力にリスナーを追加して、モジュールを続けましょう。 次の強調表示された行を追加します。
const { spawn } = require('child_process');
const child = spawn('find', ['.']);
child.stdout.on('data', data => {
console.log(`stdout:\n${data}`);
});
child.stderr.on('data', data => {
console.error(`stderr: ${data}`);
});
コマンドは、次のいずれかのデータを返すことができます。 stdout
ストリームまたは stderr
ストリームなので、両方のリスナーを追加しました。 を呼び出すことでリスナーを追加できます on()
各ストリームのオブジェクトのメソッド。 The data
ストリームからのイベントは、そのストリームへのコマンドの出力を提供します。 いずれかのストリームでデータを取得するたびに、それをコンソールに記録します。
次に、他の2つのイベントを聞きます。 error
コマンドの実行に失敗した場合、またはコマンドが中断された場合のイベント、および close
コマンドの実行が終了し、ストリームを閉じるときのイベント。
テキストエディタで、次の強調表示された行を記述してNode.jsモジュールを完成させます。
const { spawn } = require('child_process');
const child = spawn('find', ['.']);
child.stdout.on('data', (data) => {
console.log(`stdout:\n${data}`);
});
child.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
child.on('error', (error) => {
console.error(`error: ${error.message}`);
});
child.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});
のために error
と close
イベントでは、リスナーを直接設定します child
変数。 聞くとき error
イベントが発生した場合、Node.jsは Error
物体。 この場合、エラーをログに記録します message
財産。
聞いているとき close
イベントの場合、Node.jsはコマンドの終了コードを提供します。 終了コードは、コマンドが正常に実行されたかどうかを示します。 コマンドがエラーなしで実行されると、終了コードの可能な限り低い値が返されます。 0
. エラーで実行すると、ゼロ以外のコードが返されます。
モジュールが完成しました。 保存して終了 nano
と CTRL+X
.
次に、でコードを実行します node
指図:
- node findFiles.js
完了すると、次の出力が表示されます。
Outputstdout:
.
./findFiles.js
./listFiles.js
./nodejs-logo.svg
./processNodejsImage.sh
./getNodejsImage.js
child process exited with code 0
現在のディレクトリにあるすべてのファイルのリストと、コマンドの終了コードが見つかります。 0
正常に実行されたため。 現在のディレクトリには少数のファイルがありますが、このコードをホームディレクトリで実行すると、プログラムはユーザーがアクセスできるすべてのフォルダにあるすべてのファイルを一覧表示します。 それはそのような潜在的に大きな出力を持っているので、 spawn()
関数は、そのストリームが大きなバッファほど多くのメモリを必要としないため、最も理想的です。
これまで、関数を使用して子プロセスを作成し、オペレーティングシステムで外部コマンドを実行してきました。 Node.jsは、他のNode.jsプログラムを実行する子プロセスを作成する方法も提供します。 を使ってみましょう fork()
次のセクションでNode.jsモジュールの子プロセスを作成する関数。
ステップ3—で子プロセスを作成する fork()
Node.jsは fork()
関数、のバリエーション spawn()
、Node.jsプロセスでもある子プロセスを作成します。 使用の主な利点 fork()
Node.jsプロセスを作成するには spawn()
また exec()
それは fork()
親プロセスと子プロセス間の通信を可能にします。
と fork()
、子プロセスからデータを取得することに加えて、親プロセスは実行中の子プロセスにメッセージを送信できます。 同様に、子プロセスは親プロセスにメッセージを送信できます。
を使用する例を見てみましょう fork()
新しいNode.js子プロセスを作成すると、アプリケーションのパフォーマンスを向上させることができます。 Node.jsプログラムは単一のプロセスで実行されます。 したがって、大きなループの反復や大きな JSONファイルの解析などのCPUを集中的に使用するタスクは、他のJavaScriptコードの実行を停止します。 特定のアプリケーションでは、これは実行可能なオプションではありません。 Webサーバーがブロックされている場合、ブロックコードが実行を完了するまで、新しい着信要求を処理できません。
2つのエンドポイントを持つWebサーバーを作成して、これを実際に見てみましょう。 1つのエンドポイントは、Node.jsプロセスをブロックする低速の計算を実行します。 もう一方のエンドポイントは、JSONオブジェクトを返します。 hello
.
まず、という新しいファイルを作成します httpServer.js
、HTTPサーバーのコードが含まれます。
- nano httpServer.js
まず、HTTPサーバーを設定します。 これには、インポートが含まれます http
モジュール、リクエストリスナー関数の作成、サーバーオブジェクトの作成、サーバーオブジェクトでのリクエストのリッスン。 Node.jsでのHTTPサーバーの作成についてさらに詳しく知りたい場合、または復習が必要な場合は、HTTPモジュールを使用してNode.jsでWebサーバーを作成する方法に関するガイドをお読みください。
テキストエディタに次のコードを入力して、HTTPサーバーを設定します。
const http = require('http');
const host = 'localhost';
const port = 8000;
const requestListener = function (req, res) {};
const server = http.createServer(requestListener);
server.listen(port, host, () => {
console.log(`Server is running on http://${host}:${port}`);
});
このコードは、で実行されるHTTPサーバーをセットアップします http://localhost:8000
. テンプレートリテラルを使用して、そのURLを動的に生成します。
次に、50億回ループでカウントする意図的に遅い関数を記述します。 の前に requestListener()
関数、次のコードを追加します。
...
const port = 8000;
const slowFunction = () => {
let counter = 0;
while (counter < 5000000000) {
counter++;
}
return counter;
}
const requestListener = function (req, res) {};
...
これは、矢印関数構文を使用して、whileループを作成します。 5000000000
.
このモジュールを完了するには、コードをに追加する必要があります requestListener()
関数。 私たちの関数は slowFunction()
サブパスで、他のサブパスに小さなJSONメッセージを返します。 次のコードをモジュールに追加します。
...
const requestListener = function (req, res) {
if (req.url === '/total') {
let slowResult = slowFunction();
let message = `{"totalCount":${slowResult}}`;
console.log('Returning /total results');
res.setHeader('Content-Type', 'application/json');
res.writeHead(200);
res.end(message);
} else if (req.url === '/hello') {
console.log('Returning /hello results');
res.setHeader('Content-Type', 'application/json');
res.writeHead(200);
res.end(`{"message":"hello"}`);
}
};
...
ユーザーがサーバーに到達した場合 /total
サブパス、次に実行します slowFunction()
. に当たった場合 /hello
サブパス、次のJSONメッセージを返します。 {"message":"hello"}
.
を押してファイルを保存して終了します CTRL+X
.
テストするには、このサーバーモジュールを次のコマンドで実行します node
:
- node httpServer.js
サーバーが起動すると、コンソールに次のように表示されます。
OutputServer is running on http://localhost:8000
ここで、モジュールのパフォーマンスをテストするために、2つの追加の端子を開きます。 最初のターミナルでは、 curl
にリクエストを送信するコマンド /total
遅いと予想されるエンドポイント:
- curl http://localhost:8000/total
もう一方の端末では、 curl
にリクエストを送信するには /hello
このようなエンドポイント:
- curl http://localhost:8000/hello
最初のリクエストは次のJSONを返します。
Output{"totalCount":5000000000}
2番目のリクエストはこのJSONを返しますが:
Output{"message":"hello"}
へのリクエスト /hello
リクエスト後にのみ完了 /total
. The slowFunction()
ループ内にある間、他のすべてのコードの実行をブロックしました。 これは、元の端末に記録されたNode.jsサーバーの出力を確認することで確認できます。
OutputReturning /total results
Returning /hello results
着信リクエストを受け入れながらブロッキングコードを処理するには、ブロッキングコードを子プロセスに移動します。 fork()
. ブロッキングコードを独自のモジュールに移動します。 Node.jsサーバーは、誰かがアクセスしたときに子プロセスを作成します /total
エンドポイントを設定し、この子プロセスの結果をリッスンします。
最初にという新しいモジュールを作成して、サーバーをリファクタリングします。 getCount.js
含まれます slowFunction()
:
- nano getCount.js
次に、のコードを入力します slowFunction()
もう一度:
const slowFunction = () => {
let counter = 0;
while (counter < 5000000000) {
counter++;
}
return counter;
}
このモジュールはで作成された子プロセスになるため fork()
、次の場合に親プロセスと通信するためのコードを追加することもできます slowFunction()
処理が完了しました。 ユーザーに返すJSONを使用して親プロセスにメッセージを送信する次のコードブロックを追加します。
const slowFunction = () => {
let counter = 0;
while (counter < 5000000000) {
counter++;
}
return counter;
}
process.on('message', (message) => {
if (message == 'START') {
console.log('Child process received START message');
let slowResult = slowFunction();
let message = `{"totalCount":${slowResult}}`;
process.send(message);
}
});
このコードブロックを分解してみましょう。 によって作成された親プロセスと子プロセス間のメッセージ fork()
Node.jsグローバルプロセスオブジェクトを介してアクセスできます。 リスナーを追加します process
探す変数 message
イベント。 受け取ったら message
イベント、それが START
イベント。 サーバーコードは START
誰かがアクセスしたときのイベント /total
終点。 そのイベントを受け取ると、私たちは実行します slowFunction()
関数の結果を使用してJSON文字列を作成します。 を使用しております process.send()
親プロセスにメッセージを送信します。
保存して終了 getCount.js
入力して CTRL+X
ナノで。
それでは、 httpServer.js
呼び出す代わりに slowFunction()
、実行する子プロセスを作成します getCount.js
.
再度開く httpServer.js
と nano
:
- nano httpServer.js
まず、インポートします fork()
からの機能 child_process
モジュール:
const http = require('http');
const { fork } = require('child_process');
...
次に、を削除します slowFunction()
このモジュールから、 requestListener()
子プロセスを作成する関数。 次のようにファイルのコードを変更します。
...
const port = 8000;
const requestListener = function (req, res) {
if (req.url === '/total') {
const child = fork(__dirname + '/getCount');
child.on('message', (message) => {
console.log('Returning /total results');
res.setHeader('Content-Type', 'application/json');
res.writeHead(200);
res.end(message);
});
child.send('START');
} else if (req.url === '/hello') {
console.log('Returning /hello results');
res.setHeader('Content-Type', 'application/json');
res.writeHead(200);
res.end(`{"message":"hello"}`);
}
};
...
誰かが行くとき /total
エンドポイント、ここで新しい子プロセスを作成します fork()
. の議論 fork()
Node.jsモジュールへのパスです。 この場合、それは getCount.js
現在のディレクトリにあるファイル。 __dirname
. この子プロセスへの参照は変数に格納されます child
.
次に、リスナーをに追加します child
物体。 このリスナーは、子プロセスが提供するメッセージをキャプチャします。 この場合、 getCount.js
によってカウントされた総数を含むJSON文字列を返します while
ループ。 そのメッセージを受信すると、JSONをユーザーに送信します。
を使用します send()
の機能 child
メッセージを与える変数。 このプログラムはメッセージを送信します START
、の実行を開始します slowFunction()
子プロセスで。
保存して終了 nano
入力して CTRL+X
.
を使用して改善をテストするには fork()
HTTPサーバー上で作成され、実行することから始めます httpServer.js
とファイル node
:
- node httpServer.js
以前と同様に、起動時に次のメッセージが出力されます。
OutputServer is running on http://localhost:8000
サーバーをテストするには、最初に行ったように、追加の2つの端末が必要になります。 それらがまだ開いている場合は、それらを再利用できます。
最初のターミナルでは、 curl
にリクエストを送信するコマンド /total
計算に時間がかかるエンドポイント:
- curl http://localhost:8000/total
もう一方の端末では、 curl
にリクエストを送信するには /hello
短時間で応答するエンドポイント:
- curl http://localhost:8000/hello
最初のリクエストは次のJSONを返します。
Output{"totalCount":5000000000}
2番目のリクエストはこのJSONを返しますが:
Output{"message":"hello"}
これを最初に試したときとは異なり、2番目のリクエストは /hello
すぐに実行されます。 次のようなログを確認することで確認できます。
OutputChild process received START message
Returning /hello results
Returning /total results
これらのログは、 /hello
エンドポイントは、子プロセスが作成された後、子プロセスがタスクを完了する前に実行されました。
を使用して子プロセスでブロッキングコードを移動したため fork()
、サーバーは引き続き他のリクエストに応答し、他のJavaScriptコードを実行できました。 のために fork()
関数のメッセージパッシング機能。子プロセスがアクティビティを開始するタイミングを制御し、子プロセスから親プロセスにデータを返すことができます。
結論
この記事では、さまざまな関数を使用してNode.jsで子プロセスを作成しました。 最初に子プロセスを作成しました exec()
Node.jsコードからシェルコマンドを実行します。 次に、実行可能ファイルを実行しました。 execFile()
関数。 あなたは見ました spawn()
関数。コマンドを実行することもできますが、ストリームを介してデータを返し、次のようなシェルを開始しません。 exec()
と execFile()
. 最後に、 fork()
親プロセスと子プロセスの間の双方向通信を可能にする機能。
詳細については、 child_process
モジュールでは、Node.jsのドキュメントを読むことができます。 Node.jsの学習を継続したい場合は、 Node.jsシリーズのコーディング方法に戻るか、Nodeトピックページでプログラミングプロジェクトとセットアップを参照してください。