Türkiye'de ilk Mobil & PC Aynı Anda Metin2 Oyna. Triarchonline kalıcı ve uzun ömürlü yapısı ile 24 Temmuz'da açılıyor. | 1-99 Mobil Metin2 Triarch HEMEN TIKLA!
[NODE JS] child_process.fork ile Alt Process Oluşturma
Node.js tek iş parçacıklı bir yapıya sahip olsa da, bazen ağır işlemleri ana süreçten ayırmak isteyebilirsiniz. İşte tam bu noktada child_process modülünün fork metodu devreye giriyor. Ben de ilk kez büyük bir veri analiz projesinde bu ihtiyacı hissettim. Kullanıcılardan gelen raporlama istekleri, sunucunun ana event loop'unu tıkıyordu ve API yanıt süreleri felaket derecede artmıştı. fork sayesinde bu sorunu çözdüm.
fork metodu aslında child_process modülündeki spawn fonksiyonunun özelleştirilmiş bir versiyonudur. Farkı şudur: fork ile oluşturduğunuz alt süreç, ana süreçle IPC (Inter-Process Communication) kanalı üzerinden haberleşebilir. Yani ana süreç ve alt süreç birbirine mesaj gönderebilir, veri paylaşabilir. Bu, spawn veya exec ile doğrudan mümkün olmayan bir özelliktir.
Pratik olarak düşünelim. Diyelim ki bir e-ticaret siteniz var ve her gece stok raporlarını hesaplamanız gerekiyor. Bu hesaplama işlemi CPU yoğun bir iştir. Eğer bunu ana süreçte yaparsanız, o sırada gelen HTTP istekleri beklemek zorunda kalır. Ama fork ile ayrı bir süreç başlatırsanız, rapor hesaplanırken ana süreciniz rahatça istekleri karşılamaya devam eder.
fork kullanırken dikkat etmeniz gereken birkaç önemli nokta var. Birincisi, her fork çağrısı yeni bir V8 instance başlatır. Bu da yaklaşık 30-50 MB bellek tüketimi demektir. Yani yüzlerce fork oluşturmak sunucunuzu çökertebilir. İkincisi, IPC kanalı üzerinden gönderdiğiniz mesajlar JSON serileştirmesi kullanır, bu yüzden çok büyük nesneler göndermekten kaçının. Üçüncüsü, alt süreç çöktüğünde ana sürecin bunu yakalayıp uygun şekilde ele alması gerekir.
Ben projelerimde genellikle şu senaryolarda fork kullanıyorum: ağır matematiksel hesaplamalar, büyük dosya işleme operasyonları, resim veya video dönüştürme işlemleri ve uzun süren veritabanı sorguları. Her birinde ortak olan şey, bu işlemlerin ana event loop'u bloke etme potansiyeli taşımasıdır.
Bir diğer güzel özellik ise alt sürecin kendi stdin, stdout ve stderr akışlarına sahip olmasıdır. Bu sayede alt sürecin çıktılarını ayrı ayrı yönetebilirsiniz. Hata loglarını farklı bir dosyaya, normal çıktıları farklı bir yere yönlendirebilirsiniz. Üstelik alt süreç bağımsız çalıştığı için, ana süreç kapansa bile alt süreç çalışmaya devam edebilir. Tabii ki genellikle bunu istemeyiz ve alt süreçleri düzgün bir şekilde temizlememiz gerekir.
Mesaj tabanlı iletişim oldukça basittir. Ana süreçte child.send() ile mesaj gönderirsiniz, alt süreçte process.on('message') ile dinlersiniz. Tersi de geçerlidir: alt süreç process.send() ile gönderir, ana süreç child.on('message') ile dinler. Bu iki yönlü iletişim kanalı, karmaşık iş akışlarını yönetmeyi kolaylaştırır.
Son olarak, fork ile oluşturduğunuz süreçlerin yaşam döngüsünü mutlaka yönetin. Alt sürecin ne zaman başladığını, ne zaman bittiğini, hata verip vermediğini takip edin. Aksi takdirde zombie process'ler oluşabilir ve sunucunuzun belleğini yavaş yavaş tüketebilir. Aşağıdaki örneklerde tüm bu konuları detaylı şekilde göreceksiniz.
JavaScript:
// ==============================
// Ana süreç: main.js
// ==============================
const { fork } = require('child_process');
const path = require('path');
// Alt süreç dosyasının yolunu belirliyoruz
const childPath = path.join(__dirname, 'worker.js');
// fork ile alt süreç oluşturuyoruz
const child = fork(childPath);
console.log('Ana süreç PID:', process.pid);
console.log('Alt süreç başlatıldı, PID:', child.pid);
// Alt sürece görev gönderiyoruz
const gorev = {
tip: 'hesapla',
veri: [10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
islem: 'toplam'
};
child.send(gorev);
console.log('Görev alt sürece gönderildi:', gorev.islem);
// Alt süreçten gelen mesajları dinliyoruz
child.on('message', (sonuc) => {
console.log('Alt süreçten sonuç geldi:', sonuc);
if (sonuc.durum === 'tamamlandi') {
console.log('Hesaplama sonucu:', sonuc.deger);
console.log('Geçen süre:', sonuc.sure, 'ms');
}
});
// Alt süreç hata verirse yakalıyoruz
child.on('error', (hata) => {
console.error('Alt süreçte hata oluştu:', hata.message);
});
// Alt süreç kapandığında bilgi veriyoruz
child.on('exit', (kod, sinyal) => {
if (kod !== 0) {
console.error('Alt süreç hatayla kapandı. Çıkış kodu:', kod);
} else {
console.log('Alt süreç başarıyla tamamlandı.');
}
});
// ==============================
// Alt süreç: worker.js
// ==============================
process.on('message', (gorev) => {
console.log('Alt süreç görevi aldı:', gorev.tip);
const baslangic = Date.now();
let sonuc = 0;
if (gorev.islem === 'toplam') {
// Ağır hesaplama simülasyonu
for (let i = 0; i < gorev.veri.length; i++) {
sonuc += gorev.veri[i];
// CPU yoğun işlem simülasyonu
for (let j = 0; j < 1000000; j++) {
Math.sqrt(j) * Math.random();
}
}
} else if (gorev.islem === 'carpim') {
sonuc = 1;
for (let i = 0; i < gorev.veri.length; i++) {
sonuc *= gorev.veri[i];
}
}
const bitis = Date.now();
// Sonucu ana sürece gönderiyoruz
process.send({
durum: 'tamamlandi',
deger: sonuc,
sure: bitis - baslangic,
islemTipi: gorev.islem
});
});
// ==============================
// Çoklu fork yönetimi örneği
// ==============================
const { fork: forkProcess } = require('child_process');
class SurecYoneticisi {
constructor(workerDosyasi, maksimumSurec = 4) {
this.workerDosyasi = workerDosyasi;
this.maksimumSurec = maksimumSurec;
this.aktifSurecler = new Map();
this.gorevKuyrugu = [];
}
gorevEkle(gorev) {
if (this.aktifSurecler.size < this.maksimumSurec) {
this.gorevCalistir(gorev);
} else {
console.log('Kuyruk dolu, görev kuyruğa eklendi.');
this.gorevKuyrugu.push(gorev);
}
}
gorevCalistir(gorev) {
const child = forkProcess(this.workerDosyasi);
this.aktifSurecler.set(child.pid, child);
child.send(gorev);
child.on('message', (sonuc) => {
console.log(`Süreç ${child.pid} tamamlandı:`, sonuc);
});
child.on('exit', () => {
this.aktifSurecler.delete(child.pid);
// Kuyrukta bekleyen görev varsa çalıştır
if (this.gorevKuyrugu.length > 0) {
const siradakiGorev = this.gorevKuyrugu.shift();
this.gorevCalistir(siradakiGorev);
}
});
}
tumunuDurdur() {
for (const [pid, child] of this.aktifSurecler) {
console.log(`Süreç ${pid} durduruluyor...`);
child.kill('SIGTERM');
}
this.aktifSurecler.clear();
this.gorevKuyrugu = [];
}
}
// Kullanım
const yonetici = new SurecYoneticisi('./worker.js', 3);
yonetici.gorevEkle({ islem: 'toplam', veri: [1, 2, 3] });
yonetici.gorevEkle({ islem: 'carpim', veri: [4, 5, 6] });
yonetici.gorevEkle({ islem: 'toplam', veri: [7, 8, 9] });
yonetici.gorevEkle({ islem: 'carpim', veri: [10, 11, 12] });
fork metodu, Node.js'te ağır işlemleri yönetmenin en pratik yollarından biridir. Doğru kullanıldığında uygulamanızın performansını ciddi şekilde artırabilir. Ancak her alt sürecin bellek maliyeti olduğunu unutmayın ve süreç sayısını CPU çekirdek sayınıza göre sınırlayın. Bir sonraki konuda Worker Threads ile daha verimli çoklu iş parçacığı yönetimini inceleyeceğiz.
Emeğiniz ve katkınız için teşekkür ederiz!
Konunuz gerekli incelemelerden geçerek onaylandı. Topluluğumuza katkılarınızın devamını bekliyoruz.
İyi forumlar!
Konunuz gerekli incelemelerden geçerek onaylandı. Topluluğumuza katkılarınızın devamını bekliyoruz.
İyi forumlar!

Şu an konuyu görüntüleyenler (Toplam : 0, Üye: 0, Misafir: 0)
Benzer konular
- Cevaplar
- 2
- Görüntüleme
- 28
- Kilitli
- Cevaplar
- 7
- Görüntüleme
- 2K
- Kilitli
- Cevaplar
- 1
- Görüntüleme
- 448
- Cevaplar
- 15
- Görüntüleme
- 1K
- Cevaplar
- 1
- Görüntüleme
- 11
