【Node.js】Child Processを使った並列処理|CPUを活かすマルチプロセス設計

【Node.js】Child Processを使った並列処理|CPUを活かすマルチプロセス設計 Node.js

Node.jsはシングルスレッドの非同期処理で高いパフォーマンスを発揮しますが、CPUを多用する処理(画像変換・暗号化・大量計算など)ではボトルネックになることがあります。

このような場面で活躍するのが、Child Process(子プロセス)を使ったマルチプロセス処理です。Node.jsでもCPUを並列に使いこなすことで、処理速度を大きく向上できます。

Node.jsはなぜCPUに弱い?

Node.jsはイベントループでノンブロッキングI/Oを得意としますが、CPUを専有する重たい処理が1スレッド内にあると、他のリクエスト処理が詰まってしまいます。

これを解消するには、重い処理だけを別プロセスに切り出し、メインの処理と分離する必要があります。

Child Processモジュールとは

child_processモジュールは、Node.jsで新しいプロセスを生成し、親プロセスと並列に動かすことができる標準機能です。

以下の4つのメソッドがあります:

  • exec:コマンドを実行してバッファで結果を取得
  • spawn:ストリームベースで長時間実行向き
  • fork:Node.js専用スクリプトに特化(IPC通信が容易)
  • execFile:外部バイナリを直接実行

本記事では、forkによる子プロセスの作成と、プロセス間通信による並列処理の実装例を中心に解説します。

基本的なforkの使い方

まずは、子プロセス用のファイルを用意します。

child.js

// 子プロセス側
process.on('message', (msg) => {
  console.log('親からの指示:', msg);
  const result = msg.num * 2; // 重たい処理の代わり
  process.send({ result });
});

main.js

const { fork } = require('child_process');
const child = fork('./child.js');

child.send({ num: 42 });

child.on('message', (msg) => {
  console.log('子プロセスからの結果:', msg.result); // 84
});

forkを使うと、親子でsend()によるシンプルなデータ通信(IPC)が可能です。

並列処理に応用する

複数のデータセットに対して、同時に複数の子プロセスを立ち上げて処理することもできます。

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

const dataset = [10, 20, 30, 40];
const results = [];

dataset.forEach((num, index) => {
  const child = fork('./child.js');
  child.send({ num });

  child.on('message', (msg) => {
    results[index] = msg.result;
    child.kill();

    if (results.length === dataset.length) {
      console.log('全結果:', results);
    }
  });
});

このように、CPUコアを活かした並列処理が可能になります。

注意点とベストプラクティス

  • 子プロセスは独立したメモリ空間を持つため、メモリの使用量に注意
  • 大量のforkはオーバーヘッドになるため、ワーカープール(worker_threadsや外部ライブラリ)導入を検討
  • プロセス間通信(IPC)のデータサイズは必要最小限に

まとめ|Node.jsでもマルチコアを活かす

Node.jsは非同期I/Oに強みがありますが、CPU負荷の高い処理にはforkを使ったマルチプロセス設計が有効です。

child_process.forkを使えば、Node.jsのコードだけで並列処理を簡単に実現でき、CPUリソースをフルに活かしたアーキテクチャを構築できます。

さらに高度な用途では、worker_threadsclusterモジュールと組み合わせて、拡張性のあるマルチプロセス設計を目指すのもよいでしょう。