NodeJs はシングルスレッドですか?

Mar 20 2023
Nodejs で他のスレッドを操作するにはどうすればよいですか?
Node.js は JavaScript コードを単一スレッドで実行します。つまり、コードは一度に 1 つのタスクしか実行できません。
Nodejs I/O プロセス

Node.js は JavaScript コードを単一スレッドで実行します。つまり、コードは一度に 1 つのタスクしか実行できません。ただし、Node.js 自体はマルチスレッドであり、ディスクからのファイルの読み取りやネットワーク リクエストなどの I/O 操作を処理する「libuv」ライブラリを通じて隠しスレッドを提供します。Node.js は、隠しスレッドを使用することにより、メイン スレッドをブロックせずにコードで I/O リクエストを実行できる非同期メソッドを提供します。

Node.js は、worker-threads モジュールを導入しました。このモジュールを使用すると、スレッドを作成し、JavaScript タスクを並行して実行できます。スレッドがタスクを完了すると、その結果をメインスレッドで使用できるように、結果を含むメッセージがメインスレッドに送信されます。ワーカースレッドはメインスレッドをブロックしないので、タスクを分割して複数のパーに分散して最適化できます。

例を作って詳しく見てみましょう。

Nodejs プロジェクトを作成し、Express フレームワークをインストールしています

mkdir multiple-thread
cd multiple-thread
npm init -y
npm install express

まず、プロセスとスレッドがあります。私たちはそれらの違いを知っておく必要があります。

プロセスとは何ですか?

プロセスはOS上でプログラムを実行しています。一度に 1 つのタスクを実行できます。

プロセスを詳しく見てみましょう。JS ファイルを作成し、プロセスをログに記録します。

//ex-process.js

const processName = process.argv.slice(2)[0]

let count = 0;

while(true){
 count++;
 if(count === 3333 || count=== 6666){
   console.log(`${processName}: ${count}`)
 }
}

node ex-process.js FirstEx &

// & symbol means the Node program to run in the background, so we can use 
our teminal for other works

Output
[1] 82942
FirstEx: 3333
FirstEx: 6666

ps |grep node

Output
82942 ttys001    2:38.85 node ex-process.js FirstEx
83105 ttys001    0:00.00 grep node

スレッドは、アプリケーション内で複数の実行パスを実装する比較的軽量な方法です。システム レベルでは、プログラムは並行して実行され、システムはそのプログラムのニーズと他のプログラムのニーズに基づいて各プログラムに実行時間を配分します。

ノンブロッキングルートとブロッキングルートを使ってExpress Serverをコーディングしてみましょう

ユーザー向けの通常のブロック ルートをコーディングしてみましょう。でapp.js;

const express = require('express');

const app = express();

app.get('/hello', (req,res)=>{
    res.status(200).send(`Hello`);
})

app.get('/blocking-route', (req,res)=>{
    console.log('Blocking route called')
    let counter = 0;
    for (let i = 0; i < 15_000_000_000; i++) {
      counter++;
    }
    res.status(200).send(`result is ${counter}`);
})



app.listen(7333, ()=> console.log('Server started on port 7333'));

blocking-routeが完了して応答が返されるまで応答しません。

なぜ即座に応答しなかったのでしょうか?

この例では、CPU バウンドの for ループがメインスレッドをブロックします。メインスレッドがブロックされている間、Node.js は CPU バウンドのプロセスが終了するまでクエリを処理できません。したがって、他のルートはどれもルートロード/helloとして機能しません/blocking-route。

GETしたがって、のような非ブロッキング ルートへの同時リクエストが数千件ある API がある場合/hello、 への 1 つのリクエストだけで/blocking-routeAPI 内のすべてのルートがブロックされます。つまり、すべてのアプリケーション ルートが応答しなくなります。

DAAA IT の JavaScript、別のスレッドは使用できません

Dudeeee JSだけではありません。ノデイスです。ワーカースレッドを使用して、CPU に依存するタスクをオフロードできます。

nprocまず最初に、コマンドでコアをチェックする必要があります。

nproc

output
8

のような別の JS ファイルを作成しましょうworker.js。名前は自由です。このファイルでは、CPU を集中的に使用するタスクを実行します

//worker.js
const { parentPort } = require("worker_threads");

let counter = 0;
console.log("Worker started");
for (let i = 0; i < 15_000_000_000; i++) {
  counter++;
}

parentPort.postMessage(counter);

//app.js
const express = require("express");
const { Worker } = require("worker_threads");

const app = express();

app.get("/blocking-route", async (req, res) => {
  console.log("Blocking route called");
  let counter = 0;
  for (let i = 0; i < 15_000_000_000; i++) {
    counter++;
  }
  res.status(200).send(`result is ${counter}`);
});

app.get("/hello", (req, res) => {
  res.status(200).send(`Hello`);
});

app.get("/non-blocking-route", async (req, res) => {
  console.log("Non-blocking route called");
  const worker = new Worker("./worker.js");

  worker.on("message", (data) => {
    res.status(200).send(`result is ${data}`);
  });

  worker.on("error", (err) => {
    res.status(404).send(` error ${err}`);
  });

  console.log("I am not blocked");
});

app.listen(7333, () => console.log("Server started on port 7333"));

でサーバーを起動しましょうnode app.js。ブラウザを開いて、http://localhost:7333/non-blocking-route応答が返される前に に進みますhttp://localhost:7333/hello。気づきましたか?すぐに返答が得られます。ブロックはありません。他のルートの読み込みが完了するのを待ちませんでした。CPU に依存するタスクがオフロードされて別のスレッドが動作し、メインスレッドがすべてのリクエストを処理するためです。より多くのワーカーを使用してパフォーマンスを向上させることができます。たとえば、8 つのコアがあり、プロセスを 8 つに分割できます。

結論

ワーカー (スレッド) は、CPU に負荷がかかる JavaScript 操作を支援します。child_processや とは異なりcluster、worker_threadsメモリを共有できます。

この記事では、worker_threads の仕組みをわかりやすく説明してみました。

読んでくれてありがとう

>REF