Task.WhenAll vs Parallel.ForEach
.NET Core’da Task.WhenAll ve Parallel.ForEach farkı, özellikle performans ve ölçeklenebilirlik açısından çok kritik.
.NET Core’da Task.WhenAll vs Parallel.ForEach – Farkları ve Ne Zaman Hangisi Kullanılmalı?
.NET dünyasında paralel programlama denildiğinde en sık karşılaşılan iki yapı:
- Task.WhenAll
- Parallel.ForEach
İkisi de aynı amaca hizmet ediyor gibi görünse de, aslında farklı senaryolar için tasarlanmışlardır. Yanlış seçim performans kaybına ve thread starvation (iş parçacığı tükenmesi) sorunlarına yol açabilir.
Bu yazıda teknik farklarını, performans etkilerini ve doğru kullanım senaryolarını inceleyeceğiz.
Task.WhenAll Nedir?
Task.WhenAll, birden fazla asenkron işlemi başlatır ve hepsinin tamamlanmasını bekler.
Genellikle I/O-bound (veritabanı, HTTP, dosya sistemi) işlemler için kullanılır.
public async Task GetDataAsync()
{
var task1 = GetFromApiAsync();
var task2 = GetFromDatabaseAsync();
var task3 = GetFromFileAsync();
await Task.WhenAll(task1, task2, task3);
}
Nasıl Çalışır?
Task’ler başlatılır.
Thread bloklanmaz.
İşlem I/O beklerken thread havuza geri bırakılır.
Tüm task’ler tamamlandığında devam eder.
Avantajları
✅ Thread block etmez
✅ Yüksek ölçeklenebilirlik
✅ Web API ve mikroservis mimarileri için ideal
✅ Async/await ile doğal uyumlu
Parallel.ForEach Nedir?Parallel.ForEach, koleksiyon üzerindeki işlemleri çoklu thread kullanarak paralel çalıştırır.
Genellikle CPU-bound (yoğun hesaplama) işlemler için uygundur.
Parallel.ForEach(numbers, number =>
{
ProcessNumber(number);
});
Nasıl Çalışır?
- ThreadPool’dan birden fazla thread alır.
- İşlemleri paralel olarak dağıtır.
- Her işlem ayrı thread’de çalışır.
- İşlem bitene kadar thread meşgul kalır.
Avantajları
✅ CPU’yu maksimum kullanır
✅ Hesaplama yoğun işlemlerde hızlıdır
✅ Basit paralel işleme senaryolarında etkilidir
Temel Farklar
| Özellik | Task.WhenAll | Parallel.ForEach |
|---|---|---|
| Kullanım Amacı | I/O-bound işlemler | CPU-bound işlemler |
| Thread Kullanımı | Thread bloklanmaz | Thread aktif kullanılır |
| Async Desteği | Doğal async/await | Async için uygun değil |
| Web API için | ✅ Çok uygun | ❌ Riskli |
| CPU Hesaplama | ❌ Zayıf | ✅ Çok iyi |
En Büyük Hata: Parallel.ForEach ile Async Kullanmak
Şu kullanım yanlıştır:
Parallel.ForEach(items, async item =>
{
await CallApiAsync(item);
});
Bu yapı:
- Async akışı bozabilir
- Thread starvation’a sebep olabilir
- Beklenmeyen hatalar üretebilir
Bunun yerine:
await Task.WhenAll(items.Select(item => CallApiAsync(item)));
kullanılmalıdır.
Ne Zaman Hangisini Kullanmalıyım?
✔ Eğer işlem I/O ise:
- API çağrısı
- Veritabanı sorgusu
- Dosya okuma/yazma
Task.WhenAll kullan
Eğer işlem CPU-bound ise:
- Görüntü işleme
- Matematiksel hesaplama
- Büyük veri transformasyonu
Parallel.ForEach kullan
Performans Açısından Özet
Modern .NET uygulamalarında async/await mimarisi önceliklidir.
Web uygulamalarında genellikle Task.WhenAll tercih edilmelidir.
Parallel.ForEach yanlış kullanılırsa sunucunun thread pool’unu tüketebilir.
Sonuç
Her iki yapı da paralellik sağlar ancak farklı problemleri çözer:
- Task.WhenAll = Asenkron I/O paralelliği
- Parallel.ForEach = CPU paralelliği
Yanlış araç seçimi sistem performansını düşürebilir. Özellikle ASP.NET Core projelerinde varsayılan tercihiniz çoğu zaman Task.WhenAll olmalıdır.
Son yorumlar