.NET 10 Performans İyileştirmeleri: Öne Çıkanlar ve Benchmark Sonuçları

Paylaş :

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.

.NET 10 Performans İyileştirmeleri: Öne Çıkanlar ve Benchmark Sonuçları

.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)TahsisKarşılaştırma
.NET 10.03.921 ns0 B0.51x daha hızlı
.NET 9.07.703 ns72 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)TahsisPerformans
.NET 10.06,292.9 ns24 B3x daha hızlı
.NET 9.018,983.3 ns88 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.0Fark
Count (int)15.42 µs7.23 µs2x hız
Where + ToList17.64 µs14.02 µs%20 hız
Count (float)263 µs262 µ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
Deserialize1,476 ns1,353 ns%10 daha hızlı
Serialize584 ns527 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.0Fark
Minimal API (Parallel 100)3.207 ms2.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.

Hesabınızı yönetmek için giriş yapın

veya