.NET Core-da performans

.NET Core-da performans

.NET Core-da performans

Hamıya salam! Bu məqalə mənim və həmkarlarımın müxtəlif layihələr üzərində işləyərkən uzun müddət istifadə etdiyimiz Ən Yaxşı Təcrübələr toplusudur.

Hesablamaların aparıldığı maşın haqqında məlumat:BenchmarkDotNet=v0.11.5, ƏS=Windows 10.0.18362
Intel Core i5-8250U CPU 1.60GHz (Kaby Lake R), 1 CPU, 8 məntiqi və 4 fiziki nüvə
.NET Core SDK=3.0.100
[Host]: .NET Core 2.2.7 (CoreCLR 4.6.28008.02, CoreFX 4.6.28008.03), 64bit RyuJIT
Əsas: .NET Core 2.2.7 (CoreCLR 4.6.28008.02, CoreFX 4.6.28008.03), 64 bit RyuJIT
[Host]: .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT
Əsas: .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64 bit RyuJIT

İş = Əsas İş vaxtı = Əsas

ToList və ToArray və Cycles


Mən bu məlumatı .NET Core 3.0 versiyasının buraxılışı ilə hazırlamağı planlaşdırırdım, lakin onlar məni buna görə döydülər, mən başqasının şöhrətini oğurlamaq və başqalarının məlumatlarını kopyalamaq istəmirəm, ona görə də qeyd edəcəyəm müqayisənin ətraflı təsvir olunduğu yaxşı bir məqaləyə keçid.

Öz adımdan sizə ölçmələrimi və nəticələrimi təqdim etmək istəyirəm; “C++ üslubu” yazı ilmələrini sevənlər üçün onlara tərs döngələr əlavə etdim.

Kodu

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 və 3.0-da performans sürətləri demək olar ki, eynidir. .NET Core 3.0-da əldə edə bildiklərim bunlardır:

.NET Core-da performans

.NET Core-da performans

Belə nəticəyə gəlmək olar ki, Array kolleksiyasının iterativ işlənməsi onun daxili optimallaşdırılması və açıq şəkildə kolleksiya ölçüsünün ayrılması səbəbindən daha sürətli olur. Onu da xatırlamağa dəyər ki, List kolleksiyasının öz üstünlükləri var və siz tələb olunan hesablamalardan asılı olaraq düzgün kolleksiyadan istifadə etməlisiniz. Döngələrlə işləmək üçün məntiq yazsanız belə, bunun adi bir döngə olduğunu və mümkün döngə optimallaşdırılmasına da məruz qaldığını unutmayın. Uzun müddət əvvəl habr-da bir məqalə dərc olundu: https://habr.com/ru/post/124910/. Hələ də aktualdır və oxumaq tövsiyə olunur.

Atmaq

Bir il əvvəl mən bir şirkətdə köhnə bir layihə üzərində işlədim, bu layihədə cəhd-tutmaq-atmaq konstruksiyasından istifadə edərək sahənin doğruluğunun işlənməsi normal idi. Mən o zaman artıq başa düşdüm ki, bu, layihə üçün qeyri-sağlam biznes məntiqidir, ona görə də mümkün olduqda belə dizayndan istifadə etməməyə çalışırdım. Ancaq belə bir tikinti ilə səhvləri idarə etməyə yanaşmanın niyə pis olduğunu anlayaq. İki yanaşmanı müqayisə etmək üçün kiçik bir kod yazdım və hər seçim üçün etalon hazırladım.

Kodu

        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 və Core 2.2-də nəticələr oxşar nəticəyə malikdir (.NET Core 3.0):

.NET Core-da performans

.NET Core-da performans

"Try catch" kodu başa düşməyi çətinləşdirir və proqramınızın icra müddətini artırır. Ancaq bu konstruksiyaya ehtiyacınız varsa, səhvləri idarə etməsi gözlənilməyən kod sətirlərini daxil etməməlisiniz - bu kodu başa düşməyi asanlaşdıracaq. Əslində, sistemi yükləyən istisnaların idarə edilməsi deyil, yeni İstisna konstruksiyasının atılması vasitəsilə səhvlərin atılmasıdır.

İstisnaların atılması xətanı tələb olunan formatda toplayan bəzi siniflərdən daha yavaşdır. Əgər siz forma və ya bəzi məlumatları emal edirsinizsə və xətanın nə olması lazım olduğunu dəqiq bilirsinizsə, niyə onu emal etməyəsiniz?

Əgər bu vəziyyət müstəsna deyilsə, siz throw new Exception() konstruksiyasını yazmamalısınız. İstisnanın idarə edilməsi və atılması çox bahadır!!!

ToLower, ToLowerInvariant, ToUpper, ToUpperInvariant

.NET platformasında işlədiyim 5 illik təcrübə ərzində mən string matching istifadə edən bir çox layihələrlə rastlaşmışam. Aşağıdakı şəkli də gördüm: çoxlu layihələri olan bir Müəssisə həlli var idi, onların hər biri simli müqayisələri fərqli şəkildə yerinə yetirirdi. Bəs nə istifadə edilməlidir və onu necə birləşdirmək olar? Rixterin C# vasitəsilə CLR kitabında ToUpperInvariant() metodunun ToLowerInvariant() metodundan daha sürətli olması barədə məlumat oxudum.

Kitabdan çıxarış:

.NET Core-da performans

Əlbəttə ki, mən buna inanmadım və .NET Framework-də bəzi testlər keçirməyə qərar verdim və nəticə məni şoka saldı - 15%-dən çox performans artımı. Sonra ertəsi gün səhər işə gələndə bu ölçmələri rəhbərlərimə göstərdim və onlara mənbə koduna giriş imkanı verdim. Bundan sonra 2 layihədən 14-si yeni ölçülərə uyğun olaraq dəyişdirildi və bu iki layihənin nəhəng Excel cədvəllərini emal etmək üçün mövcud olduğunu nəzərə alsaq, nəticə məhsul üçün çox əhəmiyyətli oldu.

Mən də sizə .NET Core-un müxtəlif versiyaları üçün ölçmələri təqdim edirəm ki, hər biriniz ən optimal həllə doğru seçim edə biləsiniz. Və sadəcə onu əlavə etmək istəyirəm ki, işlədiyim şirkətdə sətirləri müqayisə etmək üçün ToUpper() istifadə edirik.

Kodu

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-da performans

.NET Core-da performans

.NET Core 3.0-da bu metodların hər biri üçün artım ~x2 təşkil edir və tətbiqləri öz aralarında balanslaşdırır.

.NET Core-da performans

.NET Core-da performans

Səviyyə tərtibi

Son məqaləmdə bu funksionallığı qısaca təsvir etdim, sözlərimi düzəltmək və əlavə etmək istərdim. Çoxsəviyyəli kompilyasiya həllinizin başlanğıc vaxtını sürətləndirir, lakin siz kodunuzun hissələrinin arxa planda daha optimallaşdırılmış versiyaya yığılmasını qurban verirsiniz ki, bu da kiçik əlavə xərclər yarada bilər. NET Core 3.0-ın gəlişi ilə səviyyəli tərtibetmə aktivləşdirilmiş layihələr üçün tikinti vaxtı azaldı və bu texnologiya ilə əlaqəli səhvlər düzəldildi. Əvvəllər bu texnologiya ASP.NET Core-da ilk sorğularda səhvlərə səbəb olurdu və çoxsəviyyəli kompilyasiya rejimində ilk qurma zamanı donur. Hal-hazırda .NET Core 3.0-da defolt olaraq aktivdir, lakin istəyirsinizsə, onu söndürə bilərsiniz. Əgər siz komanda rəhbəri, böyük, orta və ya şöbə müdiri vəzifəsindəsinizsə, o zaman başa düşməlisiniz ki, layihənin sürətli inkişafı komandanın dəyərini artırır və bu texnologiya sizə hər iki tərtibatçı üçün vaxta qənaət etməyə imkan verəcək. və layihənin vaxtı.

.NET səviyyəsinə yüksəldi

.NET Framework / .NET Core versiyanızı təkmilləşdirin. Çox vaxt hər bir yeni versiya əlavə performans artımı təmin edir və yeni funksiyalar əlavə edir.

Bəs faydaları tam olaraq nələrdir? Onlardan bəzilərinə nəzər salaq:

  • .NET Core 3.0 .NET Core proqramlarının işə salınma vaxtını azaldacaq R2R şəkillərini təqdim etdi.
  • 2.2 versiyası ilə Tier Compilation ortaya çıxdı, bunun sayəsində proqramçılar bir layihəni işə salmağa daha az vaxt sərf edəcəklər.
  • Yeni .NET Standartları üçün dəstək.
  • Proqramlaşdırma dilinin yeni versiyası üçün dəstək.
  • Optimallaşdırma, hər yeni versiya ilə Collection/Struct/Stream/String/Regex və daha çox əsas kitabxanaların optimallaşdırılması təkmilləşdirilir. .NET Framework-dən .NET Core-a köçürsünüzsə, qutudan böyük performans artımı əldə edəcəksiniz. Nümunə olaraq, .NET Core 3.0-a əlavə edilmiş bəzi optimallaşdırmalara keçid əlavə edirəm: https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core-3-0/

.NET Core-da performans

Nəticə

Kod yazarkən layihənizin müxtəlif aspektlərinə diqqət yetirməyə və ən yaxşı nəticəni əldə etmək üçün proqramlaşdırma dilinizin və platformanızın xüsusiyyətlərindən istifadə etməyə dəyər. .NET-də optimallaşdırma ilə bağlı biliklərinizi bölüşsəniz şad olaram.

Github-a keçid

Mənbə: www.habr.com

Добавить комментарий