NodeJs tek iş parçacıklı mı?

Mar 20 2023
Nodejs'deki diğer iş parçacıklarıyla nasıl çalışılır?
Node.js, JavaScript kodunu tek iş parçacığında çalıştırır, bu da kodunuzun aynı anda yalnızca bir görev yapabileceği anlamına gelir.
Nodejs G/Ç İşlemi

Node.js, JavaScript kodunu tek iş parçacığında çalıştırır, bu da kodunuzun aynı anda yalnızca bir görev yapabileceği anlamına gelir. Ancak Node.js'nin kendisi çok iş parçacıklıdır ve bir diskten dosya okumak veya ağ istekleri gibi G/Ç işlemlerini işleyen "libuv" kitaplığı aracılığıyla gizli iş parçacıkları sağlar. Node.js, gizli iş parçacıklarının kullanımıyla, kodunuzun ana iş parçacığını engellemeden G/Ç istekleri yapmasına izin veren eşzamansız yöntemler sağlar.

Node.js bize işçi-threads modülünü tanıttı. Bu modül, iş parçacığı oluşturmaya ve Javascript görevlerini paralel olarak yürütmeye izin verir. Bir iş parçacığı bir görevi bitirirse, ana iş parçacığına sonucu içeren bir mesaj gönderir, böylece onu ana iş parçacığında kullanabiliriz. Worker-thread'ler ana thread'i engellemez, bu yüzden onu optimize etmek için görevimizi birden fazla pars'a bölebilir ve dağıtabiliriz.

Bir örnek yapalım ve daha yakından bakalım.

Bir Nodejs projesi oluşturuyoruz ve Express çerçevesini kuruyoruz

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

Her şeyden önce, süreçler ve iş parçacıkları vardır. Aralarındaki farkları bilmeliyiz.

İşlem Nedir?

Bir işlem işletim sisteminde bir program çalıştırıyor. Bir seferde bir görevi yürütebilir.

Süreci daha yakından inceleyelim. Bir JS dosyası oluşturun ve işlemi günlüğe kaydedin.

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

İş parçacıkları, bir uygulama içinde birden çok yürütme yolu uygulamanın nispeten hafif bir yoludur. Sistem düzeyinde, programlar yan yana çalışır ve sistem, kendi ihtiyaçlarına ve diğer programların ihtiyaçlarına göre her programa yürütme süresini dağıtır.

Express Server'ı engellemeyen rota ve bloke eden rotalarla kodlayalım

Kullanıcılar için normal bir engelleme yolu kodlayalım. ; 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'));

Bitirene kadar yanıt vermez blocking-routeve bir yanıt gönderir.

Neden bize anında cevap vermedi?

Bu örnekte, CPU'ya bağlı for döngüsü ana iş parçacığını engeller. Ana iş parçacığı engellenmişken, Node.js, CPU'ya bağlı işlem sona erene kadar hiçbir sorguyu işleyemez. bu nedenle, rota yüklenirken diğer rotaların hiçbiri /helloişlev görmez /blocking-route.

GETBu nedenle, gibi engellemesiz yola binlerce eşzamanlı istek içeren bir API'miz varsa /hello, yalnızca bir istek /blocking-routeAPI'deki tüm yolları engeller. Bu, tüm uygulama yollarının yanıt vermemesine neden olduğu anlamına gelir.

DAAA IT'nin javascript'i, başka bir ileti dizisi kullanamayız

Dudeeee Sadece JS değil. Bu Nodejs. Çalışan iş parçacıklarıyla CPU'ya bağlı bir görevi boşaltabiliriz.

Öncelikle nprockomut ile çekirdeklerimizi kontrol etmeliyiz.

nproc

output
8

Gibi başka bir JS dosyası oluşturalım worker.js, isim size kalmış. Bu dosyada, CPU yoğun görevler yapıyoruz.

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

ile sunucuyu başlatalım node app.js. Tarayıcınızı açın ve http://localhost:7333/non-blocking-routebir yanıt döndürmeden gidin adresine gidin http://localhost:7333/hello. Farkına varabildin mi? Anında yanıt alıyoruz. Engelleme yok. Diğer rotaların yüklenmesini beklemedik. Çünkü CPU'ya bağlı görev boşaltılır ve başka bir iş parçacığı üzerinde çalışır ve ana iş parçacığı tüm istekleri işler. Performansımızı artırmak için daha fazla işçi kullanabiliriz. Örneğin 8 çekirdeğim var ve İşlemimi 8'e bölebilirim.

Çözüm

Çalışanlar (thread'ler), yoğun CPU kullanan JavaScript işlemlerinde yardımcı olabilir. child_processVeya aksine cluster, worker_threadshafızayı paylaşabilir.

Bu yazıda, bunu kolaylaştırmaya ve işçi_threads'in nasıl çalıştığını açıklamaya çalıştım.

Okuduğunuz İçin Teşekkürler

>REF'ler