Node.jsマルチプロセスCPU密集タスクの実現


Node.jsシングルスレッドとマルチプロセス
Node.jsの性能が高いことはよく知られています。非同期イベントで駆動され、ブロックI/Oではなく、広く使われています。しかし、欠点もはっきりしています。Node.jsはシングルスレッドプログラムなので、長時間演算すると、CPUが即時にリリースできなくなります。したがって、CPU密集型アプリケーションには適していません。
もちろん、この問題を解決する方法がないわけではない。Node.jsはマルチスレッドをサポートしていませんが、マルチプルプロセスを作成してタスクを実行することができます。
Node.jsはchild_を提供しました。processとclusterの二つのモジュールは、複数のサブプロセスを作成するために使用できます。
次に、それぞれのスレッドとプロセスを使って、大量のフィボナッチ数をシミュレーションしてCPU密集試験を行います。
以下のコードは500回の位置を検索して35のフィボナッチ数です。(テストに便利です。時間を決めました。あまり長くも短くもない場所が必要です。)
単スレッド処理
コード:single.js

function fibonacci(n) {
 if (n == 0 || n == 1) {
  return n;
 } else {
  return fibonacci(n - 1) + fibonacci(n - 2);
 }
}

let startTime = Date.now();
let totalCount = 500;
let completedCount = 0;
let n = 35;

for (let i = 0; i < totalCount; i++) {
 fibonacci(n);
 completedCount++;
 console.log(`process: ${completedCount}/${totalCount}`);
}
console.log("👏 👏 👏 👏 👏 👏 👏 👏 👏 👏");
console.info(`    ,  : ${Date.now() - startTime}ms`);
console.log("👏 👏 👏 👏 👏 👏 👏 👏 👏 👏");

node single.jsを実行して結果を調べます。
私のパソコンに表示された結果は44611 msです。

process:500/500
👏 👏 👏 👏 👏 👏 👏 👏 👏 👏
タスク完了時:44611 ms
👏 👏 👏 👏 👏 👏 👏 👏 👏 👏
500回の検索は44秒かかります。遅すぎます。位置がもっと大きいなら、数量がもっと多いと思いますが…
じゃ、私達はマルチプロセスを試してみます。⬇️
プロセス
clusterモジュールを採用して、Master-Workerモードでテストします。
全部で3つのjsです。それぞれメインスレッドコード:mater.js、サブプロセスコード:worker.js、入口コード:cluster.js(入口は単独でjsを書く必要がありません。ここでは、より明確に見えるようにします。)
メインスレッドコード:master.js

const cluster = require("cluster");
const numCPUs = require("os").cpus().length;

//          
cluster.setupMaster({
 exec: "./worker.js",
 slient: true
});

function run() {
 //       
 const startTime = Date.now();
 //   
 const totalCount = 500;
 //         
 let completedCount = 0;
 //      
 const fbGenerator = FbGenerator(totalCount);

 if (cluster.isMaster) {
  cluster.on("fork", function(worker) {
   console.log(`[master] : fork worker ${worker.id}`);
  });
  cluster.on("exit", function(worker, code, signal) {
   console.log(`[master] : worker ${worker.id} died`);
  });

  for (let i = 0; i < numCPUs; i++) {
   const worker = cluster.fork();

   //        
   worker.on("message", function(msg) {
    //     ,       
    completedCount++;
    console.log(`process: ${completedCount}/${totalCount}`);

    nextTask(this);
   });

   nextTask(worker);
  }
 } else {
  process.on("message", function(msg) {
   console.log(msg);
  });
 }

 /**
  *        
  *
  * @param {ChildProcess} worker      ,            
  */
 function nextTask(worker) {
  //        
  const data = fbGenerator.next();
  //         ,           ,    
  if (data.done) {
   done();
   return;
  }
  //       
  //         
  worker.send(data.value);
 }

 /**
  *   ,                  
  */
 function done() {
  if (completedCount >= totalCount) {
   cluster.disconnect();
   console.log("👏 👏 👏 👏 👏 👏 👏 👏 👏 👏");
   console.info(`    ,  : ${Date.now() - startTime}ms`);
   console.log("👏 👏 👏 👏 👏 👏 👏 👏 👏 👏");
  }
 }
}

/**
 *    
 */
function* FbGenerator(count) {
 var n = 35;
 for (var i = 0; i < count; i++) {
  yield n;
 }
 return;
}

module.exports = {
 run
};

1.ここでは、現在のコンピュータの論理CPUコアの数によって、サブプロセスを作成します。コンピュータの数によって違います。私のCPUは6つの物理コアです。超スレッド処理をサポートしていますので、論理コアの数は12です。だから、12個のサブプロセスを作成します。
2.メインスレッドとサブプロセスとの間の通信は、send方式でデータを送信し、MEssageイベントを傍受してデータを受信することである。
3.私がES 6を使ったジェネナートジェネレータを使って、検索するたびにフィボナッチの数の位置をシミュレーションして生成しているかどうかは分かりません。😂,上記のスレッドと統一を保証するため)。このようにするのはすべての任務を一度に投げ出さないためで、たとえ投げてもふさがれることができますとしても、まだ手順の端に置くほうがいいです。
サブプロセスコード:worker.js

function fibonacci(n) {
 if (n == 0 || n == 1) {
  return n;
 } else {
  return fibonacci(n - 1) + fibonacci(n - 2);
 }
}

//             ,          
process.on("message", n => {
 var res = fibonacci(n);
 //           ,             
 process.send(res);
});
    :cluster.js
//      js,        run  
const master = require("./master");
master.run();

node cluster.jsを実行して結果を調べます。
私のパソコンで結果を表示します。10724 msです。
process:500/500
👏 👏 👏 👏 👏 👏 👏 👏 👏 👏
タスク完了時:10724 ms
👏 👏 👏 👏 👏 👏 👏 👏 👏 👏
結果
上記の2つの方式に比べて,多プロセス処理速度は単スレッド処理速度の4倍以上であることが明らかになった。また、条件がある場合、CPUが十分であれば、プロセス数がもっと多くなり、速度も速くなります。
もっといい案や他の言語が必要とされるならもっといいです。Node.jsは生まれつきCPU密集型の応用に適しないです。
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。