Bloga dön

.NET 11 Preview 1: Async/Await Artık Runtime Tarafından Yönetiliyor

.NET 11 Preview 1: Async/Await Artık Runtime Tarafından Yönetiliyor

Geçtiğimiz ay Microsoft, .NET 11 Preview 1 sürümünü yayınladı ve öne çıkan yeniliklerden biri Runtime Async oldu. Daha önceden .NET 10’da deneysel olarak bulunan özellik .NET 11 ile varsayılan olarak geliyor. Bu değişiklik, asenkron işlemlerin yönetimini compiler’dan alıp doğrudan .NET runtime’a (CLR) devreden önemli bir davranışsal değişiklik sunuyor. Bu sayede CLR, async işlemleri artık native olarak anlayıp daha verimli bir şekilde yönetebiliyor ve optimize edebiliyor.

C# 5 ile birlikte hayatımıza giren async/await keyword’leri ile asenkron işlemleri yönetmede büyük bir kolaylık sağladık. Tabi bu durum beraberinde bazı sorunlar getirdi. Normal şartlarda asenkron bir metot, compiler tarafından IAsyncStateMachine arayüzünü implement eden bir state machine yapısına dönüştürülerek bu süreci yönetiyordu ve CLR async’i doğrudan bir execution modeli olarak bilmiyordu. State bir değişken üzerinden kontrol ediliyordu ve MoveNext adlı bir metotla bir sonraki işleme geçiliyordu. Bu da beraberinde optimizasyon problemleri ve ek allocation maliyetleri gibi birtakım sorunlar getiriyordu. Yeni çalışma modeliyle compiler bu kodu üretmek yerine görevini büyük ölçüde CLR’a bırakmış durumda.

Compiler Async’in Sorunları Nelerdir

Yüksek heap maliyeti: Asenkron metotlar için üretilen state machine yapıları, await sonrası yaşamına devam eden her değişken için field oluşturur. Metot senkron şekilde tamamlanmazsa bu yapı genellikle heap üzerinde yaşamaya devam eder. Bazı senaryolarda boxing ve ek allocation oluşabilir. Bu durum her asenkron çağrıda gerçekleşebileceği için memory maliyetini ve GC yükünü artırır.

Daha zor debug: C# zaten derin stack trace yapısına sahip ve üretilen state machine kodları bunu daha da karmaşık hale getirir. Kod debug edilirken karşımıza çıkan çok sayıda MoveNext methodu, gerçek iş akışını takip etmeyi zorlaştırır ve debug sürecini karmaşıklaştırır.

Optimizasyon sıkıntıları: Asenkron akışın büyük kısmı compiler tarafından oluşturulan state machine üzerinden yönetildiği için runtime (CLR) bu yapıyı doğrudan anlamaz, sadece çalıştırır. Bu nedenle runtime seviyesinde yapılabilecek optimizasyonlar sınırlıdır.

Daha fazla IL kodu: Üretilen state machine yapıları .NET ara diline (IL) çevrildiği için daha fazla IL kodu oluşur. Bu da JIT’in derlemesi gereken kod miktarını artırır ve dolaylı olarak performans üzerinde ek yük oluşturur.

Runtime Async Nedir

Runtime Async, asenkron metotları compiler’dan runtime’a devreder. Normal şartlarda state machine (debug’da class, release’de struct) üreten compiler, bu sefer [MethodImpl(MethodImplOptions.Async)] ile işaretlenmiş bir IL kodu üretir ve daha basit ve anlaşılabilir bir yapı koyar. Bu noktadan sonra runtime devreye girer. Askıya alma ve devam ettirme (MoveNext/continuation) işlemlerinin sorumluluğunu üstlenir, ihtiyaç duyulmayan verileri veya state machine’i heap’te tutmaz.

Asenkron metotların birbirini çağırdığı durumlarda, runtime geçişleri optimize edebilir ve async zincirlerindeki Task allocation’larını tamamen önleyebilir.

Ayrıca Native AOT desteği de mevcut; yani runtime-async metotlar AOT ile compile edilebilir. Fakat core runtime kütüphaneler henüz runtime-async desteğiyle derlenmiş değil, bu nedenle Preview 1’de bazı özellikleri denemek için proje bazında compiler desteğini açmanız gerekiyor.

Çoğu standart uygulamada ekstra bir ayar yapmanıza gerek yoktur; runtime async varsayılan olarak aktiftir.

Bunun için proje dosyasına:

<EnablePreviewFeatures>true</EnablePreviewFeatures> <Features>$(Features);runtime-async=on</Features>

ekliyoruz. Bu sayede runtime-async metotları compile edip test edebilirsiniz.

Kaynaklar: https://github.com/dotnet/core/blob/main/release-notes/11.0/preview/preview1/runtime.md https://laurentkempe.com/2026/02/14/exploring-net-11-preview-1-runtime-async-a-dive-into-the-future-of-async-in-net/ https://www.netmentor.es/entrada/en/runtime-async-net11