Performanse u .NET Core

Performanse u .NET Core

Performanse u .NET Core

Bok svima! Ovaj je članak zbirka najboljih praksi koje moji kolege i ja već dugo koristimo radeći na različitim projektima.

Podaci o stroju na kojem su izvršeni proračuni:BenchmarkDotNet=v0.11.5, OS=Windows 10.0.18362
Intel Core i5-8250U CPU 1.60 GHz (Kaby Lake R), 1 CPU, 8 logičkih i 4 fizičke jezgre
.NET Core SDK=3.0.100
[Host]: .NET Core 2.2.7 (CoreCLR 4.6.28008.02, CoreFX 4.6.28008.03), 64-bitni RyuJIT
Jezgra: .NET Core 2.2.7 (CoreCLR 4.6.28008.02, CoreFX 4.6.28008.03), 64-bitni RyuJIT
[Host]: .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64-bitni RyuJIT
Jezgra: .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64-bitni RyuJIT

Posao=Jezgra Runtime=Jezgra

ToList vs ToArray i ciklusi


Planirao sam pripremiti ove informacije s izlaskom .NET Core 3.0, ali su me preduhitrili, ne želim krasti tuđu slavu i kopirati tuđe informacije, pa ću samo istaknuti link na dobar članak gdje je usporedba detaljno opisana.

U svoje ime samo vam želim predstaviti svoja mjerenja i rezultate; dodao sam im obrnute petlje za ljubitelje "C++ stila" pisanja petlji.

Kodirati:

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;
        }
    }

Brzine performansi u .NET Core 2.2 i 3.0 gotovo su identične. Evo što sam uspio dobiti u .NET Core 3.0:

Performanse u .NET Core

Performanse u .NET Core

Možemo zaključiti da je iterativna obrada zbirke nizova brža zbog internih optimizacija i eksplicitne dodjele veličine zbirke. Također je vrijedno zapamtiti da kolekcija popisa ima svoje prednosti i trebali biste koristiti pravu kolekciju ovisno o potrebnim izračunima. Čak i ako pišete logiku za rad s petljama, ne zaboravite da je to obična petlja i da je također podložna mogućoj optimizaciji petlje. Na habru je davno izašao članak: https://habr.com/ru/post/124910/. I dalje je relevantan i preporučuje se za čitanje.

Baciti

Prije godinu dana radio sam u jednoj tvrtki na naslijeđenom projektu, u tom je projektu bilo normalno obraditi validaciju polja kroz konstrukciju pokušaj-uhvati-baci. Već tada sam shvatio da je to nezdrava poslovna logika projekta, pa sam, kad god je to bilo moguće, nastojao ne koristiti takav dizajn. Ali idemo shvatiti zašto je pristup rukovanju pogreškama s takvom konstrukcijom loš. Napisao sam mali kod za usporedbu dva pristupa i napravio mjerila za svaku opciju.

Kodirati:

        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;
        }

Rezultati u .NET Core 3.0 i Core 2.2 imaju sličan rezultat (.NET Core 3.0):

Performanse u .NET Core

Performanse u .NET Core

Try catch čini kôd težim za razumijevanje i povećava vrijeme izvršenja vašeg programa. Ali ako vam je potrebna ova konstrukcija, ne biste trebali umetati one retke koda za koje se ne očekuje da obrađuju pogreške - to će kod učiniti lakšim za razumijevanje. Zapravo, nije toliko rukovanje iznimkama ono što opterećuje sustav, već izbacivanje samih pogrešaka kroz konstrukciju throw new Exception.

Izbacivanje iznimaka je sporije od neke klase koja će prikupiti pogrešku u potrebnom formatu. Ako obrađujete obrazac ili neke podatke i jasno znate koja bi greška trebala biti, zašto je ne obraditi?

Ne biste trebali pisati konstrukciju throw new Exception() ako ova situacija nije iznimna. Rukovanje i izbacivanje iznimke je vrlo skupo!!!

ToLower, ToLowerInvariant, ToUpper, ToUpperInvariant

Tijekom mojih 5 godina iskustva rada na .NET platformi, naišao sam na mnoge projekte koji su koristili podudaranje nizova. Vidio sam i sljedeću sliku: postojalo je jedno Enterprise rješenje s mnogo projekata, od kojih je svaki različito izvodio usporedbe nizova. Ali što bi trebalo koristiti i kako to objediniti? U knjizi CLR via C# od Richtera, pročitao sam informaciju da je metoda ToUpperInvariant() brža od ToLowerInvariant().

Odlomak iz knjige:

Performanse u .NET Core

Naravno, nisam vjerovao i odlučio sam tada pokrenuti neke testove na .NET Frameworku i rezultat me šokirao - više od 15% povećanja performansi. Zatim, po dolasku na posao sljedećeg jutra, pokazao sam ta mjerenja svojim nadređenima i dao im pristup izvornom kodu. Nakon toga, 2 od 14 projekata su promijenjena kako bi se prilagodila novim mjerenjima, a s obzirom da su ova dva projekta postojala za obradu ogromnih Excel tablica, rezultat je bio više nego značajan za proizvod.

Također vam predstavljam mjere za različite verzije .NET Corea, kako bi svatko od vas mogao napraviti izbor prema najoptimalnijem rješenju. I samo želim dodati da u tvrtki u kojoj radim koristimo ToUpper() za usporedbu nizova.

Kodirati:

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();
        }

Performanse u .NET Core

Performanse u .NET Core

U .NET Core 3.0, povećanje za svaku od ovih metoda je ~x2 i uravnotežuje implementacije među sobom.

Performanse u .NET Core

Performanse u .NET Core

Kompilacija razine

U svom prošlom članku sam ukratko opisao ovu funkcionalnost, želio bih ispraviti i dopuniti svoje riječi. Kompilacija na više razina ubrzava vrijeme pokretanja vašeg rješenja, ali žrtvujete da će se dijelovi vašeg koda kompilirati u optimiziraniju verziju u pozadini, što može dovesti do malog opterećenja. S pojavom NET Core 3.0, vrijeme izgradnje za projekte s omogućenom kompilacijom razina se smanjilo, a greške povezane s ovom tehnologijom su ispravljene. Prethodno je ova tehnologija dovodila do pogrešaka u prvim zahtjevima u ASP.NET Core i zamrzavala se tijekom prve izgradnje u višerazinskom načinu kompilacije. Trenutno je omogućen prema zadanim postavkama u .NET Core 3.0, ali ga možete onemogućiti ako želite. Ako ste na poziciji team-lead-a, senior-a, middle-a ili ste voditelj odjela, tada morate shvatiti da brzi razvoj projekta povećava vrijednost tima i ova tehnologija će vam omogućiti da uštedite vrijeme i za programere. i vrijeme samog projekta.

.NET višu razinu

Nadogradite svoju verziju .NET Framework / .NET Core. Često svaka nova verzija pruža dodatna poboljšanja performansi i dodaje nove značajke.

Ali koje su točno prednosti? Pogledajmo neke od njih:

  • .NET Core 3.0 predstavio je R2R slike koje će smanjiti vrijeme pokretanja .NET Core aplikacija.
  • S verzijom 2.2 pojavila se Tier Compilation, zahvaljujući kojoj će programeri trošiti manje vremena na pokretanje projekta.
  • Podrška za nove .NET standarde.
  • Podrška za novu verziju programskog jezika.
  • Optimizacija, sa svakom novom verzijom poboljšava se optimizacija osnovnih biblioteka Collection/Struct/Stream/String/Regex i mnogo više. Ako migrirate s .NET Frameworka na .NET Core, odmah ćete dobiti veliko povećanje performansi. Kao primjer, prilažem poveznicu na neke od optimizacija koje su dodane u .NET Core 3.0: https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core-3-0/

Performanse u .NET Core

Zaključak

Prilikom pisanja koda vrijedi obratiti pozornost na različite aspekte vašeg projekta i koristiti značajke vašeg programskog jezika i platforme kako biste postigli najbolji rezultat. Bilo bi mi drago da podijelite svoje znanje o optimizaciji u .NET-u.

Link na github

Izvor: www.habr.com

Dodajte komentar