NodeJs เป็นเธรดเดียวหรือไม่

Mar 20 2023
จะทำงานกับเธรดอื่นใน Nodejs ได้อย่างไร
Node.js เรียกใช้โค้ด JavaScript ในเธรดเดียว ซึ่งหมายความว่าโค้ดของคุณสามารถทำงานได้ครั้งละหนึ่งงานเท่านั้น
กระบวนการ Nodejs I/O

Node.js เรียกใช้โค้ด JavaScript ในเธรดเดียว ซึ่งหมายความว่าโค้ดของคุณสามารถทำงานได้ครั้งละหนึ่งงานเท่านั้น แต่ Node.js นั้นทำงานแบบมัลติเธรดและมีเธรดที่ซ่อนอยู่ผ่านไลบรารี `libuv` ซึ่งจัดการการดำเนินการ I/O เช่น การอ่านไฟล์จากดิสก์หรือคำขอเครือข่าย ด้วยการใช้เธรดที่ซ่อนอยู่ Node.js มีวิธีการแบบอะซิงโครนัสที่ช่วยให้โค้ดของคุณสร้างคำขอ I/O โดยไม่ปิดกั้นเธรดหลัก

Node.js แนะนำโมดูล worker-threads ให้กับเรา โมดูลนั้นอนุญาตให้สร้างเธรดและเรียกใช้งาน Javascript พร้อมกัน หากเธรดทำงานเสร็จสิ้น มันจะส่งข้อความไปยังเธรดหลักที่มีผลลัพธ์ เพื่อให้เราสามารถใช้เธรดนั้นในเธรดหลักได้ เธรดผู้ปฏิบัติงานไม่ปิดกั้นเธรดหลัก ดังนั้น เราสามารถแบ่งและแจกจ่ายงานของเราไปยังหลายพาร์เพื่อเพิ่มประสิทธิภาพ

ลองทำตัวอย่างและดูให้ละเอียดยิ่งขึ้น

เรากำลังสร้างโครงการ Nodejs และติดตั้ง Express framework

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

ประการแรกมีกระบวนการและเธรด เราควรรู้ความแตกต่างระหว่างพวกเขา

กระบวนการคืออะไร?

กระบวนการกำลังเรียกใช้โปรแกรมในระบบปฏิบัติการ สามารถดำเนินการได้ครั้งละหนึ่งงาน

มาดูกระบวนการให้ละเอียดยิ่งขึ้น สร้างไฟล์ 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-bound for loop จะบล็อกเธรดหลัก ในขณะที่เธรดหลักถูกบล็อก Node.js จะไม่สามารถประมวลผลข้อความค้นหาใดๆ ได้จนกว่ากระบวนการที่เชื่อมโยงกับ CPU จะสิ้นสุดลง ดังนั้นจึงไม่มีเส้นทางอื่นเช่น/helloฟังก์ชั่นในขณะที่/blocking-routeโหลดเส้นทาง

ดังนั้น หากเรามี API ที่มีGETคำขอพร้อมกันหลายพันรายการไปยังเส้นทางที่ไม่ปิดกั้น เช่น/helloคำขอเดียวที่ส่งไปยัง the /blocking-routeจะปิดกั้นเส้นทางทั้งหมดใน API ซึ่งหมายความว่าเส้นทางแอปพลิเคชันทั้งหมดไม่ตอบสนอง

จาวาสคริปต์ของ DAAA IT เราไม่สามารถใช้เธรดอื่นได้

Dudeeee ไม่ใช่แค่ JS เท่านั้น มันคือ Nodejs เราสามารถออฟโหลดงานที่ผูกกับ 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 คอร์ได้

บทสรุป

ผู้ปฏิบัติงาน (เธรด) สามารถช่วยในการทำงาน JavaScript ที่ใช้ CPU มาก ไม่เหมือนกับหรือchild_processสามารถแบ่งปันหน่วยความจำclusterworker_threads

ในบทความนี้ ฉันได้พยายามทำให้ง่ายขึ้นและอธิบายว่า Worker_threads ทำงานอย่างไร

ขอบคุณที่อ่าน

>REF