Node.js child_process モジュール
Node.js はシングルスレッドの JavaScript ランタイム環境ですが、システムコマンドを実行したり他のプログラムを実行したりする必要がある場合があります。このような場合には、child_processモジュールを使用する必要があります。
child_processこのモジュールにより、Node.js アプリケーションは子プロセスを作成でき、これらの子プロセスはシステムコマンドの実行、他のスクリプトやプログラムの実行、親プロセスとの通信を行うことができます。
なぜ child_process が必要なのか?
- システムコマンドの実行:例えば、
ls、gitなどのコマンドラインツールを実行します - CPU 密集型タスクの実行:Node.js のメインスレッドのブロックを防ぎます
- 他の言語で書かれたプログラムとの連携:例えば、Python や C++ プログラムを呼び出します
- アプリケーションのパフォーマンス向上:マルチプロセスによりマルチコア CPU を最大限に活用します
子プロセスを作成する4つの方法
1. exec() - 簡単なコマンドの実行
exec()このメソッドは、簡単なシェルコマンドを実行し、出力結果をバッファリングします。
例
const { exec } = require('child_process');
exec('ls -l', (error, stdout, stderr) => {
if (error) {
console.error(`実行エラー: ${error}`);
return;
}
console.log(`標準出力:\n${stdout}`);
if (stderr) {
console.error(`標準エラー出力:\n${stderr}`);
}
});
exec('ls -l', (error, stdout, stderr) => {
if (error) {
console.error(`実行エラー: ${error}`);
return;
}
console.log(`標準出力:\n${stdout}`);
if (stderr) {
console.error(`標準エラー出力:\n${stderr}`);
}
});
特徴:
- 簡単なコマンドの実行に適しています
- 完全なバッファリングされた出力を返します
- 最大バッファサイズの制限があります(デフォルト 200KB)
2. execFile() - 実行可能ファイルの実行
execFile()exec() に似ていますexec()が、シェルを介さずにファイルを直接実行します。
例
const { execFile } = require('child_process');
execFile('node', ['--version'], (error, stdout, stderr) => {
if (error) {
throw error;
}
console.log(stdout);
});
execFile('node', ['--version'], (error, stdout, stderr) => {
if (error) {
throw error;
}
console.log(stdout);
});
特徴:
- 比
exec()より安全(シェルを介さない) - 実行効率が高い
- シェルの機能(パイプ、ワイルドカードなど)は使用できない
3. spawn() - 子プロセスのストリーム処理
spawn()このメソッドは、ストリームインターフェースを使用して子プロセスの入出力を処理します。
例
const { spawn } = require('child_process');
const ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', (data) => {
console.log(`標準出力: ${data}`);
});
ls.stderr.on('data', (data) => {
console.error(`標準エラー出力: ${data}`);
});
ls.on('close', (code) => {
console.log(`子プロセスの終了コード: ${code}`);
});
const ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', (data) => {
console.log(`標準出力: ${data}`);
});
ls.stderr.on('data', (data) => {
console.error(`標準エラー出力: ${data}`);
});
ls.on('close', (code) => {
console.log(`子プロセスの終了コード: ${code}`);
});
特徴:
- 大量の出力の処理に適しています
- ストリーム処理で、メモリ効率が高い
- 出力をリアルタイムに処理できます
4. fork() - Node.js 子プロセスの作成
fork()であるspawn()spawn() の特殊なケースであり、新しい Node.js プロセスを作成するために特別に使用されます。
例
const { fork } = require('child_process');
const child = fork('child.js');
child.on('message', (msg) => {
console.log('子プロセスからのメッセージ:', msg);
});
child.send({ hello: 'world' });
const child = fork('child.js');
child.on('message', (msg) => {
console.log('子プロセスからのメッセージ:', msg);
});
child.send({ hello: 'world' });
特徴:
- 新しい Node.js インスタンスを作成
- 組み込みの IPC(プロセス間通信)チャネル
- CPU 密集型タスクに適しています
プロセス間通信 (IPC)
親プロセスと子プロセスはsend()とmessageイベントを介して通信できます。
親プロセス (parent.js):
例
const { fork } = require('child_process');
const child = fork('child.js');
child.on('message', (msg) => {
console.log('親プロセスが受信:', msg);
});
child.send({ parent: 'Hello from parent' });
const child = fork('child.js');
child.on('message', (msg) => {
console.log('親プロセスが受信:', msg);
});
child.send({ parent: 'Hello from parent' });
子プロセス (child.js):
例
process.on('message', (msg) => {
console.log('子プロセスが受信:', msg);
process.send({ child: 'Hello from child' });
});
console.log('子プロセスが受信:', msg);
process.send({ child: 'Hello from child' });
});
エラー処理
子プロセスのエラーを適切に処理することは非常に重要です:
例
const { spawn } = require('child_process');
const child = spawn('some_command');
child.on('error', (err) => {
console.error('子プロセスの起動に失敗:', err);
});
child.stderr.on('data', (data) => {
console.error(`子プロセスエラー: ${data}`);
});
child.on('exit', (code, signal) => {
if (code) console.log(`子プロセスの終了コード: ${code}`);
if (signal) console.log(`子プロセスがシグナルで終了: ${signal}`);
});
const child = spawn('some_command');
child.on('error', (err) => {
console.error('子プロセスの起動に失敗:', err);
});
child.stderr.on('data', (data) => {
console.error(`子プロセスエラー: ${data}`);
});
child.on('exit', (code, signal) => {
if (code) console.log(`子プロセスの終了コード: ${code}`);
if (signal) console.log(`子プロセスがシグナルで終了: ${signal}`);
});
ベストプラクティス
- セキュリティ:ユーザー入力を子プロセスに直接渡さない
- リソース管理:完了した子プロセスを適時にクリーンアップする
- エラー処理:常にエラーイベントと終了イベントを処理する
- パフォーマンスへの配慮:頻繁に作成される子プロセスには、プロセスプールの使用を検討する
- クロスプラットフォーム互換性:異なるオペレーティングシステム間のコマンドの違いに注意する
まとめ
child_processこのモジュールは、Node.js で子プロセスを扱うためのコアモジュールであり、子プロセスを作成する4つの方法を提供します:
exec()- 簡単なコマンドに適していますexecFile()- 実行可能ファイルの実行に適していますspawn()- ストリーム処理に適していますfork()- Node.js 子プロセスの作成に適しています
具体的な要件に応じて適切な方法を選択し、エラー処理とリソース管理に注意することで、Node.js のマルチプロセス機能を最大限に活用できます。
その他の拡張
Node.js 組み込みモジュール