Promise ve Node.js'te Paralel İşlemler

Promise ve Node.js'te Paralel İşlemler

Nodejs'te paralel işlemler çok önemlidir ve Promise nesneleri bu işi oldukça kolaylaştırır Promise, bir işlemin sonucunu beklemek için kullanılır Bir işlem ne kadar süreceğini bilsek de, kesin sonucunu bilmediğimiz durumlarda Promise kullanabiliriz Promise'ler zincirleme halinde birbirini takip eden işlemler için kullanılabilir PromiseallSettled, bütün sonuçları döndürmek için kullanılır Promiserace ise ilk tamamlanan sonucu döndürür Cluster modülü ile Nodejs uygulamaları birden fazla işlemci çekirdeği üzerinde çalıştırılabilir ve Worker Thread modülü kullanılarak uygulama içinde birden fazla iş parçacığı oluşturulabilir Promise'lerin kullanımı daha okunaklı hale gelmek için Async ve Await anahtar kelimeleri de kullanılabilir

Promise ve Node.js'te Paralel İşlemler

Web uygulamalarının en önemli özelliklerinden biri olan paralel işlemler, Node.js için de oldukça önemlidir. Promise nesneleri, bu konuda işimizi oldukça kolaylaştırır.

Promise, Node.js'te bir işlem yürütülürken beklediğimiz sonucu döndüren bir nesnedir. Yani bir işlemin ne kadar süreceği bilinse de belli bir süre sonra sonlandığından emin olamayız. Promise, böyle bir durumda beklememizi sağlar. Bir işlem sonucu elde edildiğinde then() yöntemini kullanarak işlem sonucunda yapılacak işlemler belirlenebilir.

Birçok Promise zincirleme halinde birbirini takip eden işlemler için kullanılabilir. Promise.allSettled balk süresi tamamlandığında sonuçları döndürülmesini sağlar. Promise.race ise birden fazla Promise nesnesinin tamamlanmasını bekler ve ilk tamamlanan nesnenin sonucunu döndürür.

Node.js'in tek bir iş parçacığı üzerinde çalışması, paralel işlemler yaparken bazı sorunlar doğurabilir. Ancak Cluster modülü ile Nodejs uygulamaları birden fazla işlemci çekirdeği üzerinde çalıştırılabilir. Ayrıca Node.js 12 sürümünden itibaren Worker Thread modülü kullanılarak uygulama içinde birden fazla iş parçacığı oluşturulabilir. Böylece zorlu işlemler daha hızlı tamamlanabilir.


Promise Nedir?

Promise Nedir?

Promise, Javascript'te çoklu olaylar gerçekleştirirken işlemlerini yürütmek için kullanılan bir nesnedir. Bir işlemin ne kadar sürede tamamlanacağı bilinen veya bilinmeyen durumlarda, işlem sonucunun en sonunda nasıl işleneceğini belirlemek için kullanılır. İşlemler Promise çağrılarına bağlıdır ve Promise nesnesini bir dizi işlemi takip etmeye yönlendirir.

Promiseler, zincirleme halinde birden fazla işlemi takip etmek için kullanılabilir. Örneğin, bir kullanıcının giriş yapması gereken bir web uygulamasında, kullanıcı adı ve şifre doğru olduğunda bir dizi işlem yapılır ve her bir işlemde bir Promise kullanılabilir. Bu, kullanıcının giriş yapmasının tamamlanması için çeşitli sınavların aşılmış olması gerektiği anlamına gelir.


Promise Nasıl Kullanılır?

Promise Nasıl Kullanılır?

Promise nesnesi, bir işlemin ne kadar sürede sonuçlanacağı bilinen veya bilinmeyen bir işlem yapmak için kullanılan bir nesnedir. Bu nesnenin oluşturulması için new Promise() yöntemi kullanılır. Bu yöntem, iki parametre alır. İlk parametre, işlemin başlatılması için çalışacak olan fonksiyondur ve ikinci parametre ise işlemin sonucunu işleyen fonksiyondur. İşlem sonucu elde edilmesi için then() yöntemi kullanılır.

Örneğin:

new Promise(function(çalıştır){    setTimeout(function(){        çalıştır("Merhaba Dünya!");    }, 2000);}).then(function(sonuç){    console.log(sonuç);});

Bu örnekte, 2 saniye sonra "Merhaba Dünya!" yazdırılır.

Promise'lerin zincirleme kullanımı da mümkündür. Bu yöntemle diğer Promise'lere bağımlı işlemler yapabilmek mümkündür. Ayrıca, Async ve Await kullanarak Promise zincirlemesindeki okunabilirliği daha da artırabilirsiniz.


Promiselerin Zincirleme Kullanımı

Promiselerin zincirleme kullanımı, birçok Promise nesnesinin birbirinin ardına kullanılmasıdır. Bu yöntemle diğer Promise'lerle bağımlı işlemler yapılabilir. Bir Promise nesnesinin then() metodundan diğer bir Promise oluşturulabilir ve o Promise'nin then() metodu bir sonraki Promise oluşturmak için çağrılabilir. Bu zincirleme Promise'ler, girdilerini her bir then() metodu ile değiştirebilir veya her bir Promise için ayrı bir işlem yapılabilir.

Bir örnek verecek olursak; bir ürünün kullanıcılar tarafından beğenilip beğenilmediğini anlamak istiyoruz. İlk önce, ürünün detaylarının elde edilmesi için bir Promise nesnesi kullanabiliriz. Bu nesne then() yöntemiyle bir sonraki Promise'i çağırabilir. Sonraki Promise, ürüne ait yorumları getiren bir işlem olabilir. Bu işlem sonucunda, ürüne ait yorumların istenen kriterlere göre filtrelenmesi için bir Promise daha kullanılabilir. Bu şekilde zincirleme halinde kullanılan Promise'ler, son kullanıcının üründen memnun olup olmadığı sonucunu verir.

Zincirleme Promise kullanımı, özellikle karmaşık işlemler için oldukça kullanışlıdır. Bu yöntemle basit ve okunaklı kodlar yazılabilir. Ancak, daha fazla Promise nesnesi kullanılması kodun karmaşıklığını artırabilir. Ayrıca, bir Promise hatalı sonuç dönene kadar zincirleme Promise işlemleri devam eder.


Async ve Await Kullanımı

Async ve Await kullanarak henüz tamamlanmamış Promise'lere beklemeler eklenir. Bu yöntemle Promise zincirlemesi daha okunabilir hale getirilir. Async ve Await anahtar kelimeleri, fonksiyonlarda Promise nesnelerinin tamamlanmasını beklemek üzere kullanılır. Async anahtar kelimesi, fonksiyonlar arasında beklemeyi kolaylaştırırken, Await anahtar kelimesi, Promise nesnesinin tamamlanmasını bekler. Bu yöntem ile beraber, Promise zincirlemeleri daha okunabilir bir şekilde yazılabilir.

Aşağıdaki örnek, Async ve Await kullanarak bir Promise zincirlemesine bekleyen bir işlem ekliyor ve zincirleme daha okunabilir bir hale getiriyor:

const fetchData = () => { return new Promise((resolve, reject) => { setTimeout(() => { resolve('Data fetched successfully!'); }, 2000); }); }
async function getData () { let data = await fetchData(); console.log(data); }

Bu örnekte, fetchData adlı bir Promise nesnesi oluşturulur. getData adlı bir fonksiyon async anahtar kelimesi ile tanımlanır ve içinde fetchData() adlı bir fonksiyon await anahtar kelimesiyle kullanılır. Bu yöntemle, fetchData() tamamlanmadan getData() fonksiyonu bekleyecektir. Bu, JavaScript kodunda beklemeyi kolaylaştırır ve Promise zincirlemeleri daha okunabilir hale getirir.


Promise.all Kullanımı

Promise.all yöntemi, birden fazla Promise nesnesinin tamamlanmasını bekleyen bir yöntemdir. Şöyle bir senaryo düşünelim: Bir web uygulamasında, kullanıcının girdiği bir değeri farklı servislere istek göndererek işlem yapmak istiyoruz. Bu işlemler farklı zamanlarda tamamlanabilir ve sonuçları birleştirerek kullanıcıya sunmamız gerekiyor.

Bu durumda, Promise.all yöntemi kullanarak tüm isteklerin tamamlanmasını bekleyebilir ve sonuçları bir dizi olarak elde edebiliriz. Bu yöntem, başarılı ya da hatalı sonuçların hepsini bekler. Eğer tüm Promise'ler başarılı tamamlandıysa, dönen sonuçlar bir dizi olarak döndürülür. Fakat herhangi bir Promise hata verirse, Promise.all döndürülen sonucun tamamlanmasını bekler ve sonucun bir dizi olarak döndürülmesini sağlar.

Promise.all Kullanımı Örneği
Promise.all Kullanımı Açıklama
        const promise1 = Promise.resolve(3);        const promise2 = 42;        const promise3 = new Promise((resolve, reject) => {          setTimeout(resolve, 100, 'Başarılı!');        });                Promise.all([promise1, promise2, promise3]).then((values) => {          console.log(values); // [3, 42, "Başarılı!"]        });      

Yukarıda yapılan örnekte, 3 farklı Promise nesnesi oluşturulmuş ve bu nesneler Promise.all içinde bir dizi olarak gönderilmiştir. Tüm Promise'lerin tamamlanması beklenmiş ve sonuçlar bir dizi olarak elde edilmiştir.

Promise.all yöntemi, birden fazla Promise nesnesinin tamamlanmasını bekleyen durumlarda oldukça kullanışlı bir yöntemdir. Bu yöntem ile paralel olarak çalışan işlemlerin tamamlanmasını beklemek yerine, hepsinin tamamlanmasını bekleyerek sonuçları dizi olarak alabiliriz.


Promiseleri Paralel Kullanma Yöntemleri

Promiseler, Node.js'te paralel işlemler yapmak için kullanılan güçlü bir araçtır. Promise.allSettled ve Promise.race yöntemleri kullanarak paralel işlemler çok daha kolay ve verimli hale gelir. Promise.allSettled yöntemi, tüm Promise nesnelerinin tamamlanmasını bekler ve döndürülecek bir sonuç olmasa bile hata mesajlarıyla birlikte sonuçları döndürür. Bu yöntem, belirli bir sıraya bağlı olmadan tüm işlemlerin tamamlanmasını beklemek için kullanılabilir.

Promise.race yöntemi, birden fazla Promise nesnesinin tamamlanmasını bekler ve ilk tamamlanan Promise'in sonucunu döndürür. Bu özellik, zamanla yarışan ve en hızlı sonucu döndüren işlemlerde oldukça yardımcıdır. Örneğin, birden fazla API isteği yaparken, en hızlı sonuç döndüğünde diğer işlemleri iptal etmek gibi kullanımlar mümkündür.

Promise.allSettled ve Promise.race yöntemleri, birlikte kullanılarak daha karmaşık senaryolarda da kullanılabilir. Bu yöntemle, aynı anda birden fazla işlemi takip ederken, performansı artırabilirsiniz.


Promise.allSettled Kullanımı

Promise.allSettled Kullanımı

Promise.allSettled yöntemi, birden fazla Promise nesnesini bir dizi içinde bekler ve tüm Promise nesnelerinin tamamlanmasını bekler. Ancak Promise'lerinden biri hata alsa bile, diğerleri tamamlandığı için sonuçları dizi şeklinde döndürür.

Bu yöntem, birden fazla ayrı Promise işleminin tamamlanması gerekiyorsa ve hataların önemli olmadığı durumlarda kullanışlıdır. Örneğin, bir web sayfası birden fazla API'den veri alırken, herhangi bir API'de hata alınsa bile, diğerleri tamamlandığı için sayfanın işlevselliğini bozmadan devam etmesi sağlanabilir.


Promise.race Kullanımı

Promise.race yöntemi, birden fazla Promise nesnesinin tamamlanmasını bekleyerek, herhangi birisinin sonucunu döndürür. Bu yöntem, farklı işlemlerin aynı anda çalıştığı durumlarda kullanışlı olabilir. Örneğin, birden fazla API'den veri çekerken ve ilk olarak veri dönen API'nin sonucunu almak isterseniz Promise.race yöntemini kullanabilirsiniz.

Bir kullanım örneği olarak, A ve B API'larından veri çekilmesi gerektiğini düşünelim. Eğer A API'si 2 saniyede yanıt verirken, B API'si 4 saniyede yanıt veriyorsa ve sadece birinci veriye ihtiyacımız varsa, Promise.race yöntemi kullanarak ilk yanıtı alabiliriz. Bu durumda, iki Promise nesnesini Promise.race yöntemiyle birleştirip sonucu değerlendirebiliriz.

Kod Açıklama
        const promiseA = new Promise((resolve, reject) => {          setTimeout(() => {            resolve('A API yanıtı');          }, 2000);        });        const promiseB = new Promise((resolve, reject) => {          setTimeout(() => {            resolve('B API yanıtı');          }, 4000);        });        Promise.race([promiseA, promiseB]).then((result) => {          console.log(result); // A API yanıtı        });      
İki Promise nesnesinin Promise.race yöntemiyle birleştirilmesi ve ilk yanıtın döndürülmesi

Yukarıdaki kod örneğinde, iki Promise nesnesi oluşturuluyor ve her biri bir API'nin verilerini getiriyor. Sonrasında, bu iki nesne Promise.race() ile birleştiriliyor ve en hızlı tamamlayan nesnenin sonucu döndürülüyor. Bu örnekte, ilk yanıt A API yanıtı olduğu için console.log() ile ekrana yazdırılan sonuç A API yanıtı olacaktır.


Node.js ve Paralellik İle İlgili Sorunlar

Node.js, tek bir iş parçacığı üzerinde çalışan bir platformdur ve bu nedenle paralel işlemler yaparken bazı sorunlar yaşanabilir. Özellikle, tek iş parçacığının eş zamanlı olarak birçok görevi yapması gerektiğinde performans sorunları yaşanabilir. Bu nedenle, Node.js uygulamalarını paralel hale getirmek için farklı yöntemler kullanılır.

Cluster modülü, Node.js uygulamasını birden fazla işlemci çekirdeği üzerinde çalıştırmak için bir yöntemdir. Bu modül, tek bir Node.js prosesi içinde birden fazla iş parçacığı oluşturur ve bu iş parçacıkları ile uygulamanın paralel hale getirilmesine yardımcı olur. Bu yöntem, bazı durumlarda performans sorunlarını çözebilir.

Bununla birlikte, Node.js 12 sürümünden itibaren Worker Thread modülü kullanılarak da uygulama içinde birden fazla iş parçacığı oluşturulabilir. Bu yöntem, Cluster modülünden daha verimli ve daha hızlı çalışır.

Node.js uygulamalarında paralel işlemler yapmak performans sorunlarını çözebilirken, Cluster ve Worker Thread modülleri gibi teknolojilerin kullanımı başka sorunlara da neden olabilir. Örneğin, paralel işlemler daha fazla bellek kullanımına neden olabilir. Bu nedenle, Node.js uygulamaları geliştirilirken dikkatli bir şekilde paralelizasyon teknikleri seçilmelidir.


Cluster Modülü

Cluster modülü, Node.js'in tek bir iş parçacığı üzerinde çalışmasından kaynaklanan sorunları çözerek uygulamanın birden fazla işlemci çekirdeği üzerinde çalıştırılmasını sağlar. Bu modül sayesinde uygulama, diğer modüllere bağımlılıkları azaltılmış çoklu işlemci çekirdeklerine eşit şekilde dağıtılabilir.

Cluster modülü kullanarak Node.js uygulaması oluşturmak oldukça basittir. İlk olarak, uygulama başlatıldığında ana işlem yapılandırılır ve ardından işlemci çekirdeklerinde çalışacak işlemciler oluşturulur. Her bir işlemci, bağlantı noktalarına dağıtılmak üzere dinleyicilere sahip olur ve istekleri birbirleriyle senkronize olarak işlerler.

Cluster modülü aynı zamanda, sistemin işlemci çekirdeklerinin sayısına göre otomatik olarak işlemci adedi belirleyebilir. Ancak bu özelliğin yanı sıra, uygulamanın yavaşlamasına yol açan birçok problemi de çözümler. Örneğin, Respawn özelliği sayesinde, işlemci çekirdeği hataları otomatik olarak yeniden başlatılır ve uygulama kesintisiz olarak çalışır.

Bununla birlikte, Cluster modülü ile ilgili bazı dezavantajlar da bulunmaktadır. Özellikle, uygulamaya Birden Fazla Sunucu eklenmesi gerektiğinde, her sunucu için ayrı bir işlemci çekirdeği ayrılması kaçınılmaz hale gelir. Bu durumda, uygulamanın performansı kötü etkilenebilir ve Cluster modülü kullanımı önerilmez.


Worker Thread Modülü

Node.js'in 12. sürümünden itibaren yeni bir modül olan Worker Thread ile uygulama içinde birden fazla iş parçacığı oluşturmak mümkündür. Bu sayede iş yükü daha iyi paylaştırılabilir ve daha hızlı çalışma elde edilebilir. Worker Thread modülü, Node.js'in ana iş parçacığından farklı bir iş parçacığı oluşturarak çalışır.

Worker Thread modülü, kullanımı oldukça kolay ve basit bir yapıya sahiptir. Oluşturulan iş parçacıklarında, ana iş parçacığından farklı olarak bellek alanları ayrılmıştır ve bu sayede bir iş parçacığında meydana gelen hatalar diğer iş parçacıklarını etkilemez. Bu özellik, uygulamanın daha güvenli ve stabil çalışmasını sağlar.

Worker Thread modülü, birçok farklı senaryoda kullanılabilir. Örneğin, bir HTTP sunucusu uygulamasında, gelen isteklerin işlenmesi için farklı iş parçacıkları oluşturulabilir. Böylece, çok sayıda istek aynı anda işlenebilir ve sunucunun performansı artırılabilir. Ayrıca, karmaşık hesaplamalar, veritabanı işlemleri ve dosya işlemleri gibi işlemler de farklı iş parçacıklarına dağıtılarak daha hızlı sonuçlar elde edilebilir.


Sonuç

Node.js, tek bir iş parçacığı üzerinde çalışırken, paralel işlemler yapmak zor olabilir. Ancak Promise kullanarak Node.js'te paralel işlemler yapmak daha kolay hale gelir. Promise zincirleme kullanımı, Async ve Await yöntemi ve Promise.all yöntemi ile birden fazla Promise nesnesinin sonucu elde edilebilir.

Ancak, Node.js'de paralel çalışma konusunda diğer bazı problemler de yaşanabilir. Cluster modülü kullanarak, Node.js uygulaması birden fazla işlemci çekirdeği üzerinde çalıştırılabilir. Bu modül, uygulamayı kopyalarak her kopyayı farklı işlemci çekirdeği üzerinde çalıştırır. Bu sayede, uygulamanın paralel çalışması sağlanır. Benzer şekilde, Worker Thread modülü kullanılarak uygulama içinde birden fazla iş parçacığı oluşturulabilir.

Özetle, Promise kullanarak Node.js'te paralel işlemler yapmak daha kolay hale gelirken, paralel çalışma konusundaki diğer sorunları da Cluster ve Worker Thread modülleri ile çözülebilir.