Apakah NodeJs single-threaded?

Mar 20 2023
Bagaimana cara bekerja dengan utas lain di Nodejs?
Node.js menjalankan kode JavaScript dalam utas tunggal, yang berarti kode Anda hanya dapat melakukan satu tugas dalam satu waktu.
Proses I/O Nodejs

Node.js menjalankan kode JavaScript dalam utas tunggal, yang berarti kode Anda hanya dapat melakukan satu tugas dalam satu waktu. Tapi Node.js sendiri multithread dan menyediakan thread tersembunyi melalui library `libuv`, yang menangani operasi I/O seperti membaca file dari disk atau permintaan jaringan. Melalui penggunaan utas tersembunyi, Node.js menyediakan metode asinkron yang memungkinkan kode Anda membuat permintaan I/O tanpa memblokir utas utama.

Node.js memperkenalkan modul pekerja-utas kepada kami. Modul itu memungkinkan membuat utas dan menjalankan tugas Javascript secara paralel. Jika sebuah utas menyelesaikan tugas, ia mengirimkan pesan ke utas utama yang berisi hasilnya sehingga kita dapat menggunakannya di utas utama. Pekerja-utas tidak memblokir utas utama, jadi Kami dapat membagi dan mendistribusikan tugas kami ke beberapa par untuk mengoptimalkannya.

Mari kita buat contohnya dan melihatnya lebih dekat.

Kami sedang membuat proyek Nodejs dan menginstal kerangka kerja Express

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

Pertama-tama, ada proses dan utas. Kita harus mengetahui perbedaan di antara mereka.

Apa itu Proses?

Suatu proses sedang menjalankan program di OS. Itu dapat menjalankan satu tugas pada satu waktu.

Mari kita lihat lebih dekat prosesnya lebih dekat. Buat file JS dan catat prosesnya.

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

Utas adalah cara yang relatif ringan untuk mengimplementasikan banyak jalur eksekusi di dalam aplikasi. Pada tingkat sistem, program berjalan berdampingan, dengan sistem membagikan waktu eksekusi untuk setiap program berdasarkan kebutuhannya dan kebutuhan program lainnya.

Mari kode Express Server dengan rute non-pemblokiran dan rute pemblokiran

Mari kodekan rute pemblokiran normal untuk pengguna. Di 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'));

Itu tidak merespons sampai blocking-routeselesai dan telah mengirim kembali respons.

Mengapa itu tidak langsung menanggapi kami?

Dalam contoh ini, CPU terikat untuk loop memblokir utas utama. Saat utas utama diblokir, Node.js tidak dapat memproses kueri apa pun hingga proses terikat CPU berakhir. jadi tidak ada rute lain yang suka /helloberfungsi saat /blocking-routerute dimuat.

Jadi, jika kita memiliki API yang memiliki ribuan GETpermintaan simultan ke rute non-pemblokiran seperti /hello, hanya satu permintaan ke yang /blocking-routeakan memblokir semua rute di API. Artinya, itu membuat semua rute aplikasi tidak responsif.

Javascript DAAA IT, kami tidak dapat menggunakan utas lain

Bung Bukan hanya JS. Itu Nodejs. Kami dapat membongkar tugas yang terikat CPU dengan utas pekerja.

Pertama-tama, kita harus memeriksa inti kita dengan nprocperintah

nproc

output
8

Mari buat file JS lain seperti worker.js, namanya terserah Anda. Dalam file ini, kami melakukan tugas intensif 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"));

Mari kita mulai server dengan node app.js. Buka browser Anda dan buka http://localhost:7333/non-blocking-routesebelum mengembalikan respons ke http://localhost:7333/hello. Apakah Anda menyadarinya? Kami mendapat respons secara instan. Tidak ada pemblokiran. Kami tidak menunggu rute lain selesai memuat. Karena tugas yang terikat CPU diturunkan dan berfungsi di utas lain, dan utas utama menangani semua permintaan. Kita dapat menggunakan lebih banyak pekerja untuk meningkatkan kinerja kita. Misalnya, saya memiliki 8 inti dan saya dapat membagi Proses saya menjadi 8.

Kesimpulan

Pekerja (utas) dapat membantu dengan operasi JavaScript intensif-CPU. Tidak seperti child_processatau cluster, worker_threadsdapat berbagi memori.

Pada artikel ini, saya telah mencoba membuatnya lebih mudah dan menjelaskan Bagaimana cara kerja worker_threads?

Terima kasih sudah membaca

> REF