Size daha iyi hizmet sunabilmek için çerezleri kullanıyoruz.
Web sitemizde gezinme deneyiminizi geliştirmek, size kişiselleştirilmiş içerik ve hedefli reklamlar göstermek, web sitesi trafiğimizi analiz etmek ve ziyaretçilerimizin nereden geldiğini anlamak için çerezleri ve diğer izleme teknolojilerini kullanıyoruz.
⚠️
KVKK ve Çerez Politikası Bilgilendirmesi
6698 sayılı Kişisel Verilerin Korunması Kanunu (KVKK) ve Aydınlatma Yükümlülüğü kapsamında; web sitemizin temel fonksiyonlarının çalışabilmesi, veri güvenliğinin sağlanması ve performans analizi yapılabilmesi için zorunlu çerezlerin kullanımı gerekmektedir. Çerez kullanımını reddetmeniz halinde, teknik imkansızlıklar ve veri senkronizasyonu kesintileri nedeniyle web sitemizdeki hizmetlerden yararlanmanız mümkün olmamaktadır. Sitemizdeki içeriklere erişebilmek için çerez kullanımını onaylamanız gerekmektedir.
Asenkron ve Paralel Programlama: Task Parallel Library (TPL) ile "Non-blocking" Mimari Tasarımı
Modern yazılım dünyasında, özellikle yoğun I/O işlemleri ve karmaşık hesaplama algoritmaları söz konusu olduğunda, ana iş parçacığının (Main Thread) bloklanması kabul edilemez bir performans darboğazıdır. .NET ekosistemi, bu sorunu aşmak için Task Parallel Library (TPL) ve async/await desenlerini kullanarak, donanım kaynaklarını optimize eden “Non-blocking” (bloklamayan) bir mimari sunar. Bu yapı, sadece uygulamanın yanıt verebilirliğini artırmakla kalmaz, aynı zamanda işlemci çekirdeklerinin paralel olarak en yüksek verimle kullanılmasını sağlar.
Şekil 1: Asenkron ve Paralel Programlama: Task Parallel Library (TPL) ile “Non-blocking” Mimari Tasarımı.
1. Asenkron ve Paralel Programlama Arasındaki Kavramsal Ayrım
Teknik bir mimari tasarlamadan önce, eşzamanlılık (concurrency) ve paralellik (parallelism) arasındaki farkı netleştirmek gerekir:
Asenkron Programlama: Bir işlemin (genellikle I/O tabanlı) bitmesini beklemeden diğer işlere devam etme sanatıdır. Tek bir çekirdek üzerinde de gerçekleşebilir.
Paralel Programlama: Bir iş yükünün parçalara bölünerek birden fazla işlemci çekirdeğinde aynı anda yürütülmesidir. CPU yoğunluklu (computational-heavy) işlemler için idealdir.
2. Task Parallel Library (TPL) Mimarisi ve Task Sınıfı
TPL, System.Threading.Tasks isim alanı altında toplanan ve iş parçacığı yönetimini (Thread Management) soyutlayan bir kütüphanedir. Geliştiricinin doğrudan Thread oluşturup yönetmesi yerine, işi bir “Task” (Görev) olarak tanımlamasına ve bu görevin hangi çekirdekte, ne zaman çalışacağına Task Scheduler‘ın karar vermesine olanak tanır.
Task’ın Anatomisi ve Durum Yönetimi
Bir Task, bir işlemin gelecekteki sonucunu temsil eden bir “promise” yapısıdır.
async ve await anahtar kelimeleri, TPL üzerinde bir sentaktik şeker (syntactic sugar) sağlar ancak arkada çalışan mekanizma bir State Machine (Durum Makinesi) yapısıdır. Bir metod await satırına geldiğinde, mevcut context (bağlam) kaydedilir ve kontrol çağıran metoda (caller) geri verilir. İşlem bittiğinde, callback mekanizması ile kalınan yerden devam edilir.
Teknik Not: Task.Wait() ve .Result Tehlikesi
Asenkron bir metodu senkron olarak beklemek (.Wait() veya .Result), özellikle UI ve ASP.NET uygulamalarında Deadlock (Ölümcül Kilitlenme) riskine yol açar. “Async all the way” (başından sonuna kadar asenkron) prensibi bu yüzden kritiktir.
4. Veri Paralelliği ve Parallel Sınıfı
TPL, koleksiyonlar üzerinde işlem yaparken Parallel.For ve Parallel.ForEach gibi yapılar sunar. Bu yapılar, veriyi “partitions” (bölümler) haline getirerek mevcut işlemci çekirdeklerine dağıtır.
var data = Enumerable.Range(0, 1000000).ToList();
Parallel.ForEach(data, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, item => {
ProcessItem(item); // İşlemci çekirdeklerine dağıtılmış iş yükü});
Mimaride Dikkat Edilmesi Gerekenler:
MaxDegreeOfParallelism: Sistemin tüm kaynaklarını tüketmemek için paralel çalışan iş parçacığı sayısı sınırlandırılmalıdır.
Partitioning Overhead: Küçük iş yükleri için paralelleştirme, iş parçacığı yönetim maliyeti nedeniyle daha yavaş sonuç verebilir.
5. PLINQ (Parallel LINQ) ile Deklaratif Paralellik
LINQ sorgularını paralel hale getirmek için .AsParallel() metodu kullanılır. Bu, büyük veri setlerinde filtreleme ve sıralama işlemlerini otomatik olarak paralelleştirir.
Karmaşık sistemlerde verinin bir aşamadan diğerine asenkron olarak aktığı durumlarda System.Threading.Tasks.Dataflow kütüphanesi kullanılır. Bu kütüphane, “Actor Model” benzeri bir yapı sunarak veriyi bloklar halinde işler.
ActionBlock: Veriyi alır ve üzerinde bir işlem yapar.
TransformBlock: Veriyi alır, dönüştürür ve bir sonraki bloğa iletir.
BufferBlock: Veriyi kuyruğa alır.
7. Hata Yönetimi (Exception Handling) ve AggregateException
Asenkron ve paralel işlemlerde hatalar doğrudan fırlatılmaz; bunun yerine Task nesnesi içine gömülür. Eğer birden fazla paralel işlemde hata oluşursa, bu hatalar AggregateException içinde toplanır.
try {
await Task.WhenAll(task1, task2, task3);
}
catch (Exception ex) {
// await kullanıldığında AggregateException açılır ve ilk hata yakalanır Console.WriteLine(ex.Message);
}
8. İptal Mekanizması: CancellationToken
Bloklamayan bir mimaride, artık ihtiyaç duyulmayan (örneğin kullanıcının sayfadan ayrıldığı) işlemleri durdurmak kaynak yönetimi için elzemdir. TPL bu işlemi CancellationTokenSource ve CancellationToken yapılarıyla yönetir.
publicasync Task FetchDataAsync(CancellationToken ct) {
for (int i = 0; i < 10; i++) {
ct.ThrowIfCancellationRequested(); // İptal kontrolüawait Task.Delay(1000, ct);
}
}
9. Bellek Yönetimi ve Performans İpuçları
ValueTask Kullanımı: Eğer bir metod çoğu zaman sonucunu hemen (synchronously) döndürüyorsa, heap allocation’ı azaltmak için Task<T> yerine ValueTask<T> tercih edilmelidir.
Avoid async void: Sadece event handler’lar için async void kullanılmalı, diğer tüm durumlarda Task dönülmelidir. Hatalar async void içinde yakalanamaz ve süreci çökertebilir.
ConfigureAwait(false): Kütüphane (Library) geliştiriyorsanız, UI thread context’ine geri dönme zorunluluğu yoksa ConfigureAwait(false) kullanarak performansı artırın ve deadlock riskini azaltın.
10. İleri Seviye Senkronizasyon İlkel yapılar
Task’lar arasında paylaşılan kaynaklara erişimi yönetirken klasik lock yapısı asenkron metodlarda (await içinde) kullanılamaz. Bunun yerine asenkron uyumlu yapılar tercih edilmelidir:
SemaphoreSlim: Belirli sayıda iş parçacığının kaynağa erişmesine izin verir. await semaphore.WaitAsync() desteği sunar.
Concurrent Collections:ConcurrentDictionary, ConcurrentQueue gibi thread-safe koleksiyonlar, manuel kilit mekanizmalarına ihtiyacı ortadan kaldırır.
Microsoft.TPL.Dataflow: Karmaşık veri işleme pipeline’ları için.
Polly: Asenkron işlemlerde “Retry”, “Circuit Breaker” ve “Timeout” gibi hata tolerans mekanizmaları eklemek için.
Nito.AsyncEx: Asenkron programlama için yardımcı genişletme metodları ve senkronizasyon araçları.
Sonuç
Task Parallel Library (TPL), modern .NET geliştirmede yüksek performanslı ve ölçeklenebilir uygulamaların temel direğidir. “Non-blocking” bir mimari tasarlamak, sadece async yazmaktan ibaret değildir; bu, iş parçacığı havuzunu (Thread Pool) doğru yönetmek, context geçişlerini (context switching) optimize etmek ve veri akışını doğru kurgulamakla ilgilidir. Doğru uygulandığında TPL, donanımın sınırlarını zorlayan, akıcı ve sağlam sistemler inşa etmenizi sağlar.