Node.js, tek iş parçacıklı bir çalışma zamanı ortamı olarak bilinir, ancak bazı ağır hesaplamalar ve I/O operasyonları için arka planda bir thread pool kullanır. Bu makalede, Node.js'te thread pool boyutunun nasıl ayarlandığını, performansı nasıl etkilediğini ve bu süreçte karşılaşılabilecek bazı sorunları inceleyeceğiz. Ayrıca, örnek kodlar ve deneyler üzerinden bu kavramları detaylı olarak açıklayacağız.
Libuv, Node.js'in altında yatan I/O ve asenkron işlemleri yöneten bir kütüphanedir. Libuv, özellikle ağ işlemleri, dosya sistemi erişimleri ve bazı kriptografik işlemler gibi CPU yoğun işlemleri ana iş parçacığından alıp bir thread pool'a atayarak yönetir. Bu sayede, ana iş parçacığı diğer işlerle meşgulken ağır işlemler arka planda çalışabilir.
Varsayılan olarak, Node.js'te Libuv thread pool'unun boyutu dört thread'dir. Bu, dört asenkron işlemin paralel olarak çalışabileceği anlamına gelir. Ancak, bu boyut bazen yetersiz kalabilir ve performans sorunlarına yol açabilir.
Örnek Kod
const fs = require("node:fs");
const crypto = require("node:crypto");
console.log("Başlangıç");
fs.readFile("file.txt", "utf-8", (err, data) => {
if (err) throw err;
console.log(data);
});
console.log("Bitiş");
Yukarıdaki kodda, fs.readFile
asenkron bir I/O işlemi olarak thread pool kullanırken, crypto.pbkdf2Sync
senkron bir CPU yoğun işlemdir ve thread pool kullanmaz.
Node.js'te thread pool boyutunu artırarak performansı iyileştirebiliriz. Bunu yapmak için process.env.UV_THREADPOOL_SIZE
ortam değişkenini kullanabiliriz.
Örnek Kod
Aşağıdaki örnekte, thread pool boyutunu beş olarak ayarlayıp crypto.pbkdf2
fonksiyonunu beş kez çağırıyoruz:
const crypto = require("node:crypto");
process.env.UV_THREADPOOL_SIZE = 5; // Bu satırın üstte olduğundan emin olun
const start = Date.now();
const CALL_LIMIT = 5;
for (let i = 0; i < CALL_LIMIT; i++) {
crypto.pbkdf2("password", "salt", 100000, 512, "sha512", () => {
console.log(`Süre: ${Date.now() - start} ms`);
});
}
console.log("async");
Bu kodda, beş asenkron pbkdf2
işlemi paralel olarak çalışır ve her biri thread pool'daki bir thread'i kullanır. Bu sayede işlemler daha hızlı tamamlanır.
Deneyler ve Gözlemler
Varsayılan Boyut: 4 Thread
const crypto = require("node:crypto");
const start = Date.now();
const CALL_LIMIT = 5;
for (let i = 0; i < CALL_LIMIT; i++) {
crypto.pbkdf2("password", "salt", 100000, 512, "sha512", () => {
console.log(`Süre: ${Date.now() - start} ms`);
});
}
console.log("async");
Bu durumda, beşinci işlem diğerlerinden daha uzun sürer çünkü ilk dört işlem kendi thread'lerinde çalışırken beşinci işlem, bir thread'in boşalmasını bekler.
Thread Pool Boyutunu Artırma: 5 Thread
const crypto = require("node:crypto");
process.env.UV_THREADPOOL_SIZE = 5;
const start = Date.now();
const CALL_LIMIT = 5;
for (let i = 0; i < CALL_LIMIT; i++) {
crypto.pbkdf2("password", "salt", 100000, 512, "sha512", () => {
console.log(`Süre: ${Date.now() - start} ms`);
});
}
console.log("async");
Bu durumda, tüm işlemler neredeyse aynı sürede tamamlanır, çünkü her işlem kendi thread'inde çalışır.
CPU Çekirdeklerini Aşma: 16 Thread
const crypto = require("node:crypto");
process.env.UV_THREADPOOL_SIZE = 16;
const start = Date.now();
const CALL_LIMIT = 16;
for (let i = 0; i < CALL_LIMIT; i++) {
crypto.pbkdf2("password", "salt", 100000, 512, "sha512", () => {
console.log(`Süre: ${Date.now() - start} ms`);
});
}
console.log("async");
Bu durumda, işlemler daha uzun sürer çünkü işletim sistemi, 16 thread'i 8 çekirdek üzerinde dağıtmak zorunda kalır. Bu, her işlemin tamamlanma süresini artırır.
Bir web sunucusu örneğini ele alalım. Sunucu, yoğun olarak CPU'yu kullanan işlemler gerçekleştiriyor ve bu işlemler Node.js'in thread pool'u tarafından yönetiliyor. Eğer sunucuda aynı anda çok sayıda CPU yoğun işlem gerçekleşiyorsa ve thread pool yetersizse, işlemler sırayla işlenir ve yanıt süreleri uzar. Bu durumda, thread pool boyutunu, sunucunuzun CPU çekirdek sayısına uygun bir şekilde artırmak, paralel işlem kapasitesini artırır ve işlem sürelerini azaltır. Ancak, CPU çekirdek sayısından fazla bir thread pool boyutu ayarlamak, işlemciyi gereksiz yere yorar ve performansı düşürebilir.
CPU çekirdek sayısından daha fazla bir thread pool boyutu ayarlamak, performans üzerinde olumsuz etkilere yol açabilir. Örneğin, 8 çekirdekli bir bilgisayarda thread pool boyutunu 16'ya çıkarmak, işletim sisteminin daha fazla thread'i yönetmek için daha fazla kaynak harcaması gerektirdiği anlamına gelir. Bu durum, işlem süresinin artmasına neden olur.
Thread pool boyutunu artırmak, doğru şekilde yapıldığında performansı iyileştirebilir. Ancak, bu ayarın CPU çekirdek sayısına göre yapılması önemlidir. Aksi takdirde, beklenmedik performans düşüşleri yaşanabilir.
Node.js, bazı ağır işlemleri Libuv thread pool kullanarak yönetir.
Varsayılan olarak dört thread ile çalışır, ancak process.env.UV_THREADPOOL_SIZE
kullanarak bu boyutu artırabiliriz.
Thread pool boyutunu artırmak performansı iyileştirebilir, ancak thread sayısı CPU çekirdek sayısını aşarsa performans düşüşü yaşanabilir.
Bu makalede, Node.js'te thread pool boyutunu nasıl ayarlayacağınızı ve performansı nasıl optimize edeceğinizi öğrendik. Bu bilgiler, uygulamalarınızın daha verimli çalışmasına yardımcı olabilir.