C# ile yazdığınız her Task, her await ve her paralel döngü aslında perde arkasında tek bir devasa mekanizmaya dayanır: .NET Thread Pool. Peki, neden her iş için yeni bir thread açmıyoruz da bu havuzu kullanıyoruz?
1. Thread Açmanın Gizli Maliyeti
Birçok geliştirici new Thread() demenin basit bir işlem olduğunu sanır. Oysa bir thread oluşturmak, işletim sistemi seviyesinde pahalı bir operasyondur:
Hafıza Maliyeti: Her thread için varsayılan olarak 1 MB stack alanı ayrılır. 1000 thread açmaya kalktığınızda daha işe başlamadan 1 GB RAM tüketirsiniz.
Zaman Maliyeti: İşletim sisteminin thread'i oluşturması, kernel seviyesinde kayıtlarını tutması ve onu yönetmeye başlaması milisaniyeler sürer.
Context Switching: İşlemcinin sürekli bir thread'den diğerine atlaması, "defteri kapatıp diğerini açması" gibidir. Bu geçişler sırasında CPU zamanının büyük kısmı iş yapmak yerine yönetimle harcanır.
İşte Thread Pool tam burada devreye girer: Thread'leri "kullan-at" yerine "kiralık araç" mantığıyla yönetir. İş biter, thread havuza döner ve sıradaki görevi bekler.
2. Thread Pool Nasıl Çalışır? (Work-Stealing Algoritması)
Thread Pool sadece bir "liste" değildir; içinde akıllı bir iş dağıtım zekası barındırır. Modern .NET dünyasında bu, Work-Stealing (İş Çalma) algoritması ile yönetilir:
Global Queue:
Task.Runile başlattığınız işler önce genel bir kuyruğa düşer.Local Queues: Her Thread Pool thread'inin kendine ait bir yerel kuyruğu vardır. Bu, thread'ler arasındaki çekişmeyi (contention) azaltır.
Work Stealing (İş Çalma): Eğer bir thread kendi kuyruğundaki işleri bitirirse, boş durmak yerine gider diğer yoğun thread'lerin kuyruğundan iş "çalar". Bu sayede işlemci çekirdekleri her zaman dengeli bir yükle çalışır.
3. Hill Climbing Algoritması
Thread Pool, havuzdaki thread sayısını sabit tutmaz. Hill Climbing adı verilen bir algoritma ile sürekli sistemi izler:
"Eğer havuzdaki thread sayısını 1 artırırsam, saniyede bitirilen iş sayısı (throughput) artıyor mu?" sorusunu sorar.
Eğer sayı arttığında performans artıyorsa thread eklemeye devam eder. Eğer performans düşüyorsa (context switch maliyeti yüzünden), thread sayısını azaltır.
Eğer asenkron kodun içinde .Result veya .Wait() kullanarak thread'i bloke ederseniz, Hill Climbing algoritması durumu yanlış anlar. "Thread'ler çalışıyor ama iş bitmiyor, o zaman yeni thread açmalıyım" der. Sürekli yeni thread açılır, bellek şişer ve sistem sonunda Thread Pool Starvation ile yere çakılır.
