.NET Core'da performans

Herkese selam! Bu makale, meslektaşlarım ve benim farklı projeler üzerinde çalışırken uzun süredir kullandığımız En İyi Uygulamaların bir derlemesidir.
Hesaplamaların yapıldığı makineye ilişkin bilgiler:BenchmarkDotNet=v0.11.5, OS=Windows 10.0.18362
Intel Core i5-8250U CPU 1.60 GHz (Kaby Lake R), 1 CPU, 8 mantıksal ve 4 fiziksel çekirdek
.NET Core SDK=3.0.100
[Ana Bilgisayar]: .NET Core 2.2.7 (CoreCLR 4.6.28008.02, CoreFX 4.6.28008.03), 64bit RyuJIT
Çekirdek: .NET Core 2.2.7 (CoreCLR 4.6.28008.02, CoreFX 4.6.28008.03), 64bit RyuJIT
[Ana Bilgisayar]: .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT
Çekirdek: .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT
İş=Çekirdek Çalışma Zamanı=Çekirdek
ToList vs ToArray ve Döngüler
Bu bilgiyi .NET Core 3.0'ın çıkışıyla hazırlamayı planladım ama onlar bunda benden önce davrandılar, başkasının şerefini çalmak ve başkalarının bilgilerini kopyalamak istemiyorum, bu yüzden sadece şunu belirteceğim: .
Kendi adıma ölçümlerimi ve sonuçlarımı sizlere sunmak istiyorum; “C++ tarzı” yazma döngülerini sevenler için bunlara ters döngüler ekledim.
Kod:
public class Bench
{
private List<int> _list;
private int[] _array;
[Params(100000, 10000000)] public int N;
[GlobalSetup]
public void Setup()
{
const int MIN = 1;
const int MAX = 10;
Random random = new Random();
_list = Enumerable.Repeat(0, N).Select(i => random.Next(MIN, MAX)).ToList();
_array = _list.ToArray();
}
[Benchmark]
public int ForList()
{
int total = 0;
for (int i = 0; i < _list.Count; i++)
{
total += _list[i];
}
return total;
}
[Benchmark]
public int ForListFromEnd()
{
int total = 0;t
for (int i = _list.Count-1; i > 0; i--)
{
total += _list[i];
}
return total;
}
[Benchmark]
public int ForeachList()
{
int total = 0;
foreach (int i in _list)
{
total += i;
}
return total;
}
[Benchmark]
public int ForeachArray()
{
int total = 0;
foreach (int i in _array)
{
total += i;
}
return total;
}
[Benchmark]
public int ForArray()
{
int total = 0;
for (int i = 0; i < _array.Length; i++)
{
total += _array[i];
}
return total;
}
[Benchmark]
public int ForArrayFromEnd()
{
int total = 0;
for (int i = _array.Length-1; i > 0; i--)
{
total += _array[i];
}
return total;
}
}
.NET Core 2.2 ve 3.0'daki performans hızları neredeyse aynıdır. .NET Core 3.0'da şunları elde edebildim:


Bir Array koleksiyonunun yinelemeli işlenmesinin, dahili optimizasyonları ve açık koleksiyon boyutu tahsisi nedeniyle daha hızlı olduğu sonucuna varabiliriz. List koleksiyonunun kendine has avantajları olduğunu ve gerekli hesaplamalara göre doğru koleksiyonu kullanmanız gerektiğini de hatırlamakta fayda var. Döngülerle çalışmanın mantığını yazsanız bile bunun sıradan bir döngü olduğunu ve olası döngü optimizasyonuna da tabi olduğunu unutmayın. Habr'da uzun zaman önce bir makale yayınlandı: . Hala konuyla alakalıdır ve okunması tavsiye edilir.
Atmak
Bir yıl önce bir şirkette eski bir proje üzerinde çalıştım; bu projede alan doğrulamasını dene-yakala-at yapısı aracılığıyla işlemek normaldi. Bunun proje için sağlıksız bir iş mantığı olduğunu o zaman anlamıştım, bu yüzden mümkün olduğunca böyle bir tasarım kullanmamaya çalıştım. Ancak böyle bir yapıda hataları ele alma yaklaşımının neden kötü olduğunu anlayalım. İki yaklaşımı karşılaştırmak için küçük bir kod yazdım ve her seçenek için kıyaslamalar yaptım.
Kod:
public bool ContainsHash()
{
bool result = false;
foreach (var file in _files)
{
var extension = Path.GetExtension(file);
if (_hash.Contains(extension))
result = true;
}
return result;
}
public bool ContainsHashTryCatch()
{
bool result = false;
try
{
foreach (var file in _files)
{
var extension = Path.GetExtension(file);
if (_hash.Contains(extension))
result = true;
}
if(!result)
throw new Exception("false");
}
catch (Exception e)
{
result = false;
}
return result;
}
.NET Core 3.0 ve Core 2.2'deki sonuçlar benzer bir sonuca sahiptir (.NET Core 3.0):


Try catch, kodun anlaşılmasını zorlaştırır ve programınızın yürütme süresini artırır. Ancak bu yapıya ihtiyacınız varsa, hataları işlemesi beklenmeyen kod satırlarını eklememelisiniz; bu, kodun anlaşılmasını kolaylaştıracaktır. Aslında, sistemi yükleyen şey istisnaların ele alınmasından çok, yeni İstisna yapısı aracılığıyla hataların kendilerinin atılmasıdır.
İstisnaların atılması, hatayı gerekli formatta toplayacak bazı sınıflardan daha yavaştır. Bir formu veya bazı verileri işliyorsanız ve hatanın ne olması gerektiğini açıkça biliyorsanız neden işlemeyesiniz?
Bu durum istisnai değilse throw new Exception() yapısı yazmamalısınız. Bir istisnayı ele almak ve atmak çok pahalıdır!!!
ToLower, ToLowerInvariant, ToUpper, ToUpperInvariant
.NET platformunda çalıştığım 5 yıllık deneyimim boyunca, dize eşleştirmeyi kullanan birçok projeyle karşılaştım. Ayrıca şu resmi de gördüm: Her biri farklı şekilde dize karşılaştırmaları gerçekleştiren birçok projeye sahip bir Kurumsal çözüm vardı. Peki ne kullanılmalı ve nasıl birleştirilmelidir? Richter'in CLR via C# kitabında ToUpperInvariant() yönteminin ToLowerInvariant() yönteminden daha hızlı olduğu bilgisini okudum.
Kitaptan alıntı:

Elbette buna inanmadım ve .NET Framework üzerinde bazı testler yapmaya karar verdim ve sonuç beni şok etti - %15'ten fazla performans artışı. Daha sonra ertesi sabah işe geldiğimde bu ölçümleri amirlerime gösterdim ve kaynak koduna erişmelerine izin verdim. Bundan sonra 2 projeden 14'si yeni ölçümlere uyacak şekilde değiştirildi ve bu iki projenin devasa Excel tablolarını işlemek için var olduğu göz önüne alındığında sonuç, ürün için fazlasıyla anlamlıydı.
Ayrıca .NET Core'un farklı sürümlerine ait ölçümleri de sizlere sunuyorum, böylece her biriniz en uygun çözüme doğru seçim yapabilirsiniz. Şunu da eklemek istiyorum, çalıştığım şirkette dizeleri karşılaştırmak için ToUpper() kullanıyoruz.
Kod:
public const string defaultString = "VXTDuob5YhummuDq1PPXOHE4PbrRjYfBjcHdFs8UcKSAHOCGievbUItWhU3ovCmRALgdZUG1CB0sQ4iMj8Z1ZfkML2owvfkOKxBCoFUAN4VLd4I8ietmlsS5PtdQEn6zEgy1uCVZXiXuubd0xM5ONVZBqDu6nOVq1GQloEjeRN8jXrj0MVUexB9aIECs7caKGddpuut3";
[Benchmark]
public bool ToLower()
{
return defaultString.ToLower() == defaultString.ToLower();
}
[Benchmark]
public bool ToLowerInvariant()
{
return defaultString.ToLowerInvariant() == defaultString.ToLowerInvariant();
}
[Benchmark]
public bool ToUpper()
{
return defaultString.ToUpper() == defaultString.ToUpper();
}
[Benchmark]
public bool ToUpperInvariant()
{
return defaultString.ToUpperInvariant() == defaultString.ToUpperInvariant();
}


.NET Core 3.0'da bu yöntemlerin her biri için artış ~x2 olup uygulamaları kendi aralarında dengeler.


Seviye Derlemesi
Geçen yazımda bu işlevselliği kısaca anlatmıştım, sözlerimi düzeltmek ve tamamlamak istiyorum. Çok düzeyli derleme, çözümünüzün başlangıç süresini hızlandırır, ancak kodunuzun bazı bölümlerinin arka planda daha optimize edilmiş bir sürümde derlenmesinden fedakarlık edersiniz, bu da küçük bir ek yük getirebilir. NET Core 3.0'ın gelişiyle birlikte katman derlemesinin etkin olduğu projelerin yapım süresi azaldı ve bu teknolojiyle ilgili hatalar düzeltildi. Daha önce bu teknoloji, ASP.NET Core'daki ilk isteklerde hatalara yol açıyordu ve çok düzeyli derleme modunda ilk derleme sırasında donmalara yol açıyordu. Şu anda .NET Core 3.0'da varsayılan olarak etkindir ancak isterseniz devre dışı bırakabilirsiniz. Ekip lideri, kıdemli, orta veya departman başkanı iseniz, hızlı proje geliştirmenin ekibin değerini artırdığını ve bu teknolojinin her iki geliştiriciye de zaman kazandıracağını anlamalısınız. ve projenin kendisinin zamanı.
.NET seviye atlama
.NET Framework / .NET Core sürümünüzü yükseltin. Genellikle her yeni sürüm ek performans kazanımları sağlar ve yeni özellikler ekler.
Peki faydaları tam olarak nedir? Bunlardan bazılarına bakalım:
- .NET Core 3.0, .NET Core uygulamalarının başlatma süresini kısaltacak R2R görüntülerini kullanıma sundu.
- Sürüm 2.2 ile birlikte, programcıların bir projeyi başlatmak için daha az zaman harcayacağı Tier Compilation ortaya çıktı.
- Yeni .NET Standartları desteği.
- Programlama dilinin yeni bir sürümü için destek.
- Optimizasyon, her yeni sürümle birlikte Collection/Struct/Stream/String/Regex temel kitaplıklarının optimizasyonu ve çok daha fazlası geliştirilir. .NET Framework'ten .NET Core'a geçiş yapıyorsanız, büyük bir performans artışı elde edeceksiniz. Örnek olarak, .NET Core 3.0'a eklenen bazı optimizasyonların bağlantısını ekliyorum:

Sonuç
Kod yazarken projenizin farklı yönlerine dikkat etmeniz ve en iyi sonucu elde etmek için programlama dilinizin ve platformunuzun özelliklerini kullanmanız önemlidir. .NET'te optimizasyon ile ilgili bilgilerinizi paylaşırsanız sevinirim.
Kaynak: habr.com
