Ist NodeJs Single-Threaded?

Mar 20 2023
Wie arbeite ich mit anderen Threads in Nodejs?
Node.js führt JavaScript-Code in einem einzelnen Thread aus, was bedeutet, dass Ihr Code jeweils nur eine Aufgabe ausführen kann.
NodeJS-E/A-Prozess

Node.js führt JavaScript-Code in einem einzelnen Thread aus, was bedeutet, dass Ihr Code jeweils nur eine Aufgabe ausführen kann. Aber Node.js selbst ist multithreaded und stellt versteckte Threads über die „libuv“-Bibliothek bereit, die E/A-Vorgänge wie das Lesen von Dateien von einer Festplatte oder Netzwerkanfragen verarbeitet. Durch die Verwendung versteckter Threads stellt Node.js asynchrone Methoden bereit, die es Ihrem Code ermöglichen, E/A-Anfragen zu stellen, ohne den Hauptthread zu blockieren.

Node.js hat uns das Worker-Threads-Modul vorgestellt. Dieses Modul ermöglicht das Erstellen von Threads und das parallele Ausführen von Javascript-Aufgaben. Wenn ein Thread eine Aufgabe abschließt, sendet er eine Nachricht an den Hauptthread, die das Ergebnis enthält, damit wir es im Hauptthread verwenden können. Worker-Threads blockieren den Haupt-Thread nicht, daher können wir unsere Aufgabe aufteilen und auf mehrere Pars verteilen, um sie zu optimieren.

Machen wir ein Beispiel daraus und schauen wir uns das genauer an.

Wir erstellen ein Nodejs-Projekt und installieren das Express-Framework

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

Zunächst einmal gibt es Prozesse und Threads. Wir sollten die Unterschiede zwischen ihnen kennen.

Was ist Prozess?

Ein Prozess führt ein Programm im Betriebssystem aus. Es kann jeweils eine Aufgabe ausgeführt werden.

Schauen wir uns den Prozess genauer an. Erstellen Sie eine JS-Datei und protokollieren Sie den Vorgang.

//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

Threads sind eine relativ einfache Möglichkeit, mehrere Ausführungspfade innerhalb einer Anwendung zu implementieren. Auf Systemebene laufen Programme nebeneinander, wobei das System jedem Programm entsprechend seinen Anforderungen und denen anderer Programme Ausführungszeit zuteilt.

Lassen Sie uns Express Server mit der nicht blockierenden Route und den blockierenden Routen codieren

Lassen Sie uns eine normale Blockierungsroute für Benutzer codieren. Im 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'));

Es antwortet erst, wenn blocking-routees fertig ist und eine Antwort zurückgesendet hat.

Warum hat es uns nicht sofort geantwortet?

In diesem Beispiel blockiert eine CPU-gebundene for-Schleife den Hauptthread. Während der Hauptthread blockiert ist, kann Node.js keine Abfragen verarbeiten, bis der CPU-gebundene Prozess beendet ist. /helloDaher funktioniert keine der anderen Routen ähnlich , wenn die /blocking-routeRoute geladen wird.

Wenn wir also eine API haben, die Tausende von gleichzeitigen GETAnfragen an die nicht blockierende Route hat, wie zum Beispiel /hello, blockiert nur eine Anfrage an /blocking-routealle Routen in der API. Das bedeutet, dass alle Anwendungsrouten nicht mehr reagieren.

DAAA IT's Javascript, wir können keinen anderen Thread verwenden

Dudeeee Es ist nicht nur JS. Es ist Nodejs. Wir können eine CPU-gebundene Aufgabe mit Worker-Threads auslagern.

Zunächst sollten wir unsere Kerne mit nprocdem Befehl überprüfen

nproc

output
8

Lassen Sie uns eine weitere JS-Datei wie erstellen worker.js. Der Name liegt bei Ihnen. In dieser Datei erledigen wir CPU-intensive Aufgaben

//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"));

Starten wir den Server mit node app.js. Öffnen Sie Ihren Browser und gehen Sie http://localhost:7333/non-blocking-routezu, bevor er eine Antwort zurückgibt http://localhost:7333/hello. Hast du es bemerkt? Wir erhalten umgehend eine Antwort. Es gibt keine Blockierung. Wir haben nicht darauf gewartet, dass die anderen Routen vollständig geladen sind. Weil die CPU-gebundene Aufgabe entlastet ist und ein anderer Thread arbeitet und der Hauptthread alle Anfragen verarbeitet. Wir können mehr Arbeitskräfte einsetzen, um unsere Leistung zu verbessern. Ich habe zum Beispiel 8 Kerne und kann meinen Prozess in 8 aufteilen.

Abschluss

Worker (Threads) können bei CPU-intensiven JavaScript-Vorgängen helfen. Im Gegensatz zu or child_processkann der Speicher gemeinsam genutzt werden.clusterworker_threads

In diesem Artikel habe ich versucht, es einfacher zu machen und zu erklären, wie worker_threads funktioniert.

Danke fürs Lesen

>REFs