.NET 10 Performans İyileştirmeleri: Öne Çıkanlar ve Benchmark Sonuçları
Üzeyir AYDIN
12 KasHer yıl olduğu gibi, .NET ekibi de çalışma zamanı (runtime) ve kütüphanelerde performansı artırmak için iyileştirmeler yaptı. Bu yazıda, öne çıkan bazı değişiklikleri ele alacağız. İlgili blog yazılarına veya GitHub başlıklarına bağlantılar da ekledim; ilgini çeken konuları detaylıca inceleyebilirsin.

.NET 10 Performans İyileştirmeleri: Öne Çıkanlar ve Benchmark Sonuçları
Her yıl olduğu gibi, .NET ekibi de çalışma zamanı (runtime) ve kütüphanelerde performansı artırmak için iyileştirmeler yaptı. Bu yazıda, öne çıkan bazı değişiklikleri ele alacağız.
İlgili blog yazılarına veya GitHub başlıklarına bağlantılar da ekledim; ilgini çeken konuları detaylıca inceleyebilirsin.
Ve tabii ki: Makalenin sonunda benchmark sonuçlarını bulacaksın.
⚠️ Uyarı:
Tüm benchmark yazılarımda belirttiğim gibi, bu sonuçları kodunu değiştirmek için bir gerekçe olarak kullanma.
Bu testler yalnızca .NET çalışma zamanının neler yapabildiğini ve belirli senaryolarda performansı nasıl iyileştirdiğini göstermek içindir.
Her zaman kendi kodunu ölç ve gerçekten fayda sağlayıp sağlamadığını gör.
Burada gösterilen kod örnekleri izole edilmiştir ve gerçek dünya senaryolarını temsil etmez.
Sonuçlar, kullanım senaryosuna, çalışma ortamına ve diğer faktörlere göre değişebilir.
BenchmarkDotNet Çıktısı
Benim test ortamımdaki BenchmarkDotNet referans çıktısı şöyle:
BenchmarkDotNet v0.15.0, macOS Sequoia 15.5 (24F74) [Darwin 24.5.0] Apple M2 Pro, 1 CPU, 12 çekirdek (12 mantıksal, 12 fiziksel) .NET SDK 10.0.100-preview.5.25277.114 [Host] : .NET 9.0.5 (9.0.525.21509), Arm64 RyuJIT AdvSIMD .NET 10.0 : .NET 10.0.0 (10.0.25.27814), Arm64 RyuJIT AdvSIMD .NET 9.0 : .NET 9.0.5 (9.0.525.21509), Arm64 RyuJIT AdvSIMD
Stackalloc (Yığın Üzerinde Dizi Oluşturma)
Aşağıdaki kodu düşünelim:
public int StackallocOfArrays() { int[] numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; var sum = 0; for (var i = 0; i < numbers.Length; i++) sum += numbers[i]; return sum; }
Buradaki numbers dizisi normalde heap üzerinde oluşturulur.
Ancak JIT derleyicisi, dizinin küçük olduğunu ve metot kapsamı dışına çıkmayacağını tespit ederse, diziyi stack (yığın) üzerinde oluşturabilir.
Sonuçlar:
| Metot | .NET Sürümü | Ortalama (ns) | Tahsis | Karşılaştırma |
|---|---|---|---|---|
| .NET 10.0 | 3.921 ns | 0 B | 0.51x daha hızlı | |
| .NET 9.0 | 7.703 ns | 72 B | — |
Görüldüğü gibi, tahsisatlar tamamen ortadan kalkıyor çünkü dizi artık yığın üzerinde oluşturuluyor.
Performans da önemli ölçüde artıyor.
🔗 Daha fazlası için Microsoft dokümanı
Delegate Escape Analysis (Delege Kaçış Analizi)
Bir delegate oluşturduğunda, JIT analiz ederek bu delegat’in metot kapsamı dışına çıkıp çıkmayacağını belirleyebiliyor.
Normalde bir delegate oluşturulduğunda, o anki bağlamı (context) yakalar.
Bu genellikle bir sınıf örneği oluşturarak yapılır.
Ama eğer delegate metodun dışına çıkmıyorsa (örneğin başka yere dönmüyor veya saklanmıyorsa), JIT bunu optimize eder ve stack üzerinde oluşturur.
public int DelegateEscapeAnalysis() { var sum = 0; Action<int> action = i => sum += i; foreach (var number in Numbers) action(number); return sum; }
Sonuçlar:
| .NET Sürümü | Ortalama (ns) | Tahsis | Performans |
|---|---|---|---|
| .NET 10.0 | 6,292.9 ns | 24 B | 3x daha hızlı |
| .NET 9.0 | 18,983.3 ns | 88 B | — |
3 kat hızlanma ve 3 kat daha az bellek kullanımı!
🔗 Daha fazlası için GitHub sürüm notu
LINQ İyileştirmeleri
LINQ hepimizin favorisi.
.NET 10 ile birlikte LINQ operasyonlarında da yeni SIMD tabanlı hızlandırmalar yapıldı.
(SIMD hakkında daha fazla bilgi istersen: “LINQ on steroids with SIMD” başlıklı makaleye göz atabilirsin.)
Örnek kod:
public class LinqTests { private static readonly IReadOnlyCollection<int> Numbers = Enumerable.Range(0, 20000).ToArray(); private static readonly IReadOnlyCollection<float> NumbersFloats = Enumerable.Range(0, 20000).Select(s => (float)s).ToArray(); [Benchmark] public int EvenCountInteger() => Numbers.Count(n => n % 2 == 0); [Benchmark] public IReadOnlyCollection<int> EvenCountIntegerToList() => Numbers.Where(n => n % 2 == 0).ToList(); [Benchmark] public int EvenCountFloat() => NumbersFloats.Count(n => n % 2 == 0); }
Sonuçlar:
| Metot | .NET 9.0 | .NET 10.0 | Fark |
|---|---|---|---|
| Count (int) | 15.42 µs | 7.23 µs | 2x hız |
| Where + ToList | 17.64 µs | 14.02 µs | %20 hız |
| Count (float) | 263 µs | 262 µs | — |
Yorum:int türlerinde ciddi hızlanma var.float veya double türlerinde SIMD henüz devreye girmediği için fark yok.
💡 Not: Test mimarim ARM64 (MacBook Pro M2). x64 veya x86 mimarilerinde sonuçlar farklılık gösterebilir.
System.Text.Json İyileştirmeleri
Yıllardır olduğu gibi System.Text.Json kütüphanesi de küçük ama değerli performans iyileştirmeleri aldı.
Test edilen işlemler:
JSON’dan nesneye dönüştürme (
Deserialize)Nesneden JSON’a dönüştürme (
Serialize)
Sonuçlar:
| İşlem | .NET 9.0 | .NET 10.0 | İyileşme |
|---|---|---|---|
| Deserialize | 1,476 ns | 1,353 ns | %10 daha hızlı |
| Serialize | 584 ns | 527 ns | %10 daha hızlı |
Bu geliştirmeler özellikle ASP.NET API’leri için doğrudan performans kazancı sağlıyor.
ASP.NET Minimal API Performansı
Daha önce “Minimal API vs Klasik Controller” karşılaştırmasını yapmıştım.
Şimdi aynı testi .NET 10 için yeniden çalıştırdım:
| İşlem | .NET 9.0 | .NET 10.0 | Fark |
|---|---|---|---|
| Minimal API (Parallel 100) | 3.207 ms | 2.971 ms | %7 hızlanma |
ASP.NET Minimal API’leri zaten çok hızlıydı — şimdi daha da verimli hale geldi.
Sonuç
.NET 10, performans konusunda anlamlı adımlar atmaya devam ediyor:
✅ Küçük diziler için stack allocation
✅ Delegat’lerde kaçış analizi (escape analysis)
✅ LINQ SIMD iyileştirmeleri
✅ System.Text.Json hız kazanımı
✅ ASP.NET Minimal API performans artışı
Her zamanki gibi, bu benchmark’lar rehberdir ama kendi kodunuzu ölçmeden değişiklik yapmayın.
Performans kazanımları senaryoya göre farklılık gösterebilir.
Müşteri Girişi
Hesabınızı yönetmek için giriş yapın