Görev veya Görev sınıflarının kullanmasında önceki makalelerde bahsetmediğimiz bir performans darboğazı var. Kısacası, bu dersler sonuçlar hemen erişilebilir olduğunda önde gelirGereksiz tahsis。 Bu, sonuç zaten mevcut olsa bile her zaman yeni bir Görev veya Görev nesnesi oluşturulacağı anlamına gelir. Şimdi, önceki makalelerde kullandığımız asenkron/bekleme kavramının .NET 4.5 sürümünden beri var olduğunu belirtmiştik. Bu özellik, C#7'den itibaren .NET 4.7 sürümüyle geliştirilmiştir; bu yapı asenkron fonksiyonlar için dönüş olarak kullanılabilen ValueTask yapısına sahiptir.
ValueTask yapısı
ValueTask yapısı ilk olarak 2015 yılında corefxlab deposunda ortaya çıktı. Bu depo, ana corefx deposuna ulaşabilecek veya girmeyebilecek yeni fikirleri denemek ve keşfetmek için kullanılır. Corefx deposu, tüm .NET Core temel kütüphanelerinin bulunduğu depodur. Stephen Taub tarafından System.Threading.Tasks.Channels kütüphanesi için geliştirilip önerilmiştir. O dönemde Stephen kısa bir açıklama yaptı:
Corefxlab kütüphane adresi:Bağlantı girişi görünür.
ValueTask, T ve Task'ın ayrı bir birleşimidir ve ReadAsync'in mevcut T değerlerini senkron olarak döndürmesini serbest bırakabilir (Task.FromResult kullanıldığında ise bir Görev örneği tahsisi gerektirir). ValueTask beklenebil, bu yüzden çoğu durumun tüketimi görev tüketiminden ayırt edilemez. Birçok kişi, C# 7'de System.Threading.Tasks.Extensions NuGet paketinin bir parçası olarak yer alan bu yapının faydalarını görüyor. Bu yüzden, ValueTask yapısına dalmadan önce, bu sorunu çözmek için kullandığı problemi inceleyelim. Görev(Görev) bir referans tipi olduğundan, şöyle başlayınGörev nesnesini geri döndüren eşzamansız yöntem, her seferinde yığın üzerinde tahsis edildiği anlamına gelir。 Bu birçok durumda gereklidir.
Ancak bazı durumlarda, asenkron yöntemler sonuçları hemen veya tamamen eşzamanla döndürür. Bu durumlarda, bu tahsis gereksizdir ve kodun performans açısından kritik kısımlarında pahalı hale gelebilir. .NET 4.7 sürümüne kadar bunu önlemenin bir yolu yoktu; çünkü asenkron yöntemler Task, Task veya void döndürmek <T>zorundaydı (sonuncusu genellikle istenmeyen bir yöntemdi). .NET'in bu sürümünde bu genişletilmiştir; yani asenkron bir metod, erişilebilir bir GetAwaiter yöntemi olduğu sürece herhangi bir türü döndürebilir. ValueTask bu türün somut bir örneğidir ve bu sürüme de eklenmiştir.
Corefx deposunu gezdirip ValueTask'ın tam uygulamasını görebilirsiniz, işte ilgilendiğimiz API bölümü:
Bir yapı olarak, ValueTask senkron çalışma zamanı sırasında bellek tahsis etmeyen asenkron yöntemler yazmaya olanak tanır. Asenkron/bekleme kavramının API tutarlılığı bu şekilde tehlikeye girmez. Buna ek olarak, bu yapı kendi başına bekler, bu da kullanımını kolaylaştırır. Örneğin, bu basit kodu çalıştırırsak:
MultiplyAsync yönteminde, Görev kullanmaktan kaçınmak ve sadece basit bir tam sayı döndürmek istediğimiz bir durumu simüle ediyoruz. Bu, yöntemin if ifadesinde yapılır; burada temelde geçilen parametrenin sıfır olup olmadığını kontrol ediyoruz. Sorun şu kiIf ifadesindeki koşulumuz doğru olsa bile, yukarıdaki kod bir Görev nesnesi oluşturur。 Bu problemi şöyle çözüyoruz:
ValueTask ve Görev
Daha önce belirtildiği gibi, ValueTask'ı kullanmanın iki ana faydası vardır:
- Performans iyileştirmeleri
- Uygulama esnekliğini artırmak
Peki, performans iyileştirmelerinin arkasındaki rakamlar nelerdir? Bu kodu gözlemleyin:
Bu kodu çalıştırırsak, JIT'in çalıştırılması 120ns sürer. Şimdi, Task'ı ValueTask ile değiştirirsek, şöyle:
JIT ile 65ns bir uygulama süresi elde edeceğiz. Şimdi, Task.Delay nedeniyle eşzamanlı çalıştırılmadığımız doğru, ancak uygulama süresinde bir iyileşme görüyoruz.
Bahsettiğimiz bir diğer avantaj ise uygulamada artan esnekliktir. Peki, bu tam olarak ne anlama geliyor? Senkronize edilmesi gereken asenkron arayüzlerin uygulamaları ise Task.Run veya Task.FromResult kullanmak zorunda kalacak. Tabii ki, bu da daha önce tartıştığımız performans sorunlarına yol açıyor. ValueTask kullandığımızda, senkron veya asenkron uygulamalar arasında seçim yapma olasılığımız daha yüksek. Unutmayın, bu durum başınıza gelirse kodunuzun iyi tasarlanmadığının bir işareti olabilir.
Örneğin, şu arayüzü gözlemleyin:
Diyelim ki bunu böyle bir koddan çağırmak istiyorsunuz:
Arayüzde ValueTask kullandığımız için, arayüzün uygulanması senkron veya asenkron olabilir. Bu faydayı, senkronizasyon davranışını yöneten bazı fonksiyonları eklemeyi temelde atlayarak elde edebiliriz. Bu arayüzü bu şekilde kullanmak çok daha kolay. İşte yukarıdaki arayüzün eşzamanlı bir uygulaması:
İşte aynı arayüzün asenkron bir uygulaması:
Ancak, ValueTask'ı kullanmadan önce bazı takasları göz önünde bulundurmalıyız. ValueTask'ın varsayılan olarak Task yerine kullanılması gerektiğini düşünmek kolay, ki bu kesinlikle doğru değil. Örneğin, ValueTask sonuç senkronizasyonu mevcut olduğunda gereksiz atamalardan kaçınmamıza yardımcı olsa da, iki alan da içerir.
Burada kullandığımız yapının bu olduğunu unutmamak önemli; yani değer türlerini ve tüm yüklerini kullanıyoruz. Görev ise, yalnızca bir alana sahip bir referans türüdür.ValueTask'ı kullandığınızda, işlememiz ve işlememiz gereken daha fazla veri olur. Eğer böyle bir yöntem asenkron bir yöntemde bekleniyorsa, asenkron yöntemDevlet makinesi de daha büyük olacak, çünkü tüm yapının depolanması genellikle tek bir referansı depolamaktan daha fazla alan gerektirir.
Bu yüzden Microsoft'taki kişiler, asenkron yöntemler için varsayılan dönüş türü olarak Görev veya Görev kullanmayı öneriyor. Performans analizinden sonra ValueTask'a geçişi düşünmelisiniz.
özet
ValueTask, .NET 4.7'de tanıtılan ve .NET'te asenkron yöntemler kullanmamız için birçok olasılık sunan bir yapıdır. Ancak bunun bir bedeli vardır. Bu, performans açısından kritik ve eşzamanlı olarak uygulanan yöntemler için faydalıdır. Onlarla gereksiz nesneler atamaktan kaçınabiliriz. Yine de, bir değer tipi olarak, genellikle değer tiplerinin yaşadığı tüm sorunları beraberinde getirir. Bu nedenle, bu yapıdan faydalanabiliriz, ancak dikkatli olmalıyız.
Orijinal adres:Bağlantı girişi görünür.
|