Përformanca në .NET Core

Përformanca në .NET Core

Përformanca në .NET Core

Përshëndetje të gjithëve! Ky artikull është një përmbledhje e Best Practices që unë dhe kolegët e mi i kemi aplikuar për një kohë të gjatë në projekte të ndryshme.

Informacion mbi makinën në të cilën janë kryer llogaritjet:BenchmarkDotNet=v0.11.5, OS=Windows 10.0.18362
Intel Core i5-8250U CPU 1.60GHz (Kaby Lake R), 1 CPU, 8 bërthama logjike dhe 4 fizike
.NET Core SDK=3.0.100
[Host]: .NET Core 2.2.7 (CoreCLR 4.6.28008.02, CoreFX 4.6.28008.03), 64bit RyuJIT
Core: .NET Core 2.2.7 (CoreCLR 4.6.28008.02, CoreFX 4.6.28008.03), 64bit RyuJIT
[Host]: .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT
Core: .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT

Job=Core Runtime=Core

ToList vs ToArray dhe Cyklat


Këtë informacion unë e kam planifikuar ta përgatis me daljen e .NET Core 3.0, por u kam paraprirë, nuk dua të vjedh lavdinë e të tjerëve dhe të kopjoj informacionin e huaj, prandaj do të veçoj një lidhje për një artikull të mirë, ku është bërë përshkrimi i detajuar i krahasimit.

Nga ana ime, dĂ«shiroj t'ju paraqes matjet dhe rezultatet e mia, tĂ« cilat pĂ«rmbajnĂ« cikle tĂ« kundĂ«rta pĂ«r ata qĂ« preferojnĂ« stilin e shkrimit tĂ« cikleve “C++”.

Kodi:

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

Shpejtësia e punës në .NET Core 2.2 dhe 3.0 është pothuajse identike. Ky është rezultati që kam arritur në .NET Core 3.0:

Përformanca në .NET Core

Përformanca në .NET Core

Mund të arrijmë te përfundimi se përpunimi ciklik i koleksioneve të tipit Array është më i shpejtë, falë optimizimeve të brendshme dhe alokimit të qartë të madhësisë së koleksionit. Gjithashtu, duhet të mbani mend se koleksioni i tipit List ka avantazhet e veta dhe duhet të përdorni koleksionin e duhur në varësi të llogaritjeve të nevojshme. Edhe nëse shkruani logjikën e punës me cikle, mos harroni se ky është një loop i zakonshëm dhe gjithashtu mund të përfshihet në optimizimin e cikleve. Në habr një artikull është publikuar prej kohësh: https://habr.com/ru/post/124910/. Ai është ende aktual dhe rekomandohet për t'u lexuar.

Throw

NjĂ« vit mĂ« parĂ«, punoja nĂ« njĂ« kompani pĂ«r njĂ« projekt legacy, atje ishte normale tĂ« pĂ«rpunoheshin validimet e fushave pĂ«rmes strukturĂ«s try-catch-throw. NĂ« atĂ« kohĂ« e kuptoja se kjo ishte njĂ« logjikĂ« e papĂ«rshtatshme pĂ«r biznesin, prandaj sa mĂ« shumĂ« qĂ« tĂ« ishte e mundur, pĂ«rpiqesha tĂ« mos pĂ«rdorja njĂ« strukturĂ« tĂ« tillĂ«. Por le tĂ« shohim se çfarĂ« Ă«shtĂ« e keqe nĂ« kĂ«tĂ« qasje pĂ«r tĂ« trajtuar gabimet me kĂ«tĂ« strukturĂ«. Kam shkruar njĂ« kod tĂ« vogĂ«l pĂ«r tĂ« krahasuar dy qasje dhe kam bĂ«rĂ« “benc” pĂ«r secilĂ«n variant.

Kodi:

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

Rezultatet në .NET Core 3.0 dhe Core 2.2 kanë rezultate të ngjashme (.NET Core 3.0):

Përformanca në .NET Core

Përformanca në .NET Core

Try catch e komplikon kuptimin e kodit dhe rrit kohĂ«n e ekzekutimit tĂ« programit tuaj. Por nĂ«se ju nevojitet kjo strukturĂ«, mos e vendosni atĂ« rresht kodin, nga i cili nuk pritet pĂ«rpunimi i gabimeve — kjo do ta lehtĂ«sojĂ« kuptimin e kodit. NĂ« tĂ« vĂ«rtetĂ«, sa mĂ« shumĂ« rreziqe tĂ« pĂ«rfshihen, aq mĂ« pak e ngarkojnĂ« sistemin pĂ«rshkrimi i gabimeve, sesa hedhja e vetĂ« gabimeve pĂ«rmes strukturĂ«s throw new Exception.

Hidhja e përjashtimeve funksionon më ngadalë se ndonjë klasë tjetër që do të mbledhë gabimin në formatin e nevojshëm. Nëse po përpunoni një formular ose ndonjë të dhënë dhe e dini me qartë se cili duhet të jetë gabimi, atëherë pse të mos i trajtoni ato?

Mos shkruani strukturën throw new Exception() nëse kjo situatë nuk është përjashtim. Përpunimi dhe hedhja e një përjashtimi është shumë e shtrenjtë!!!

ToLower, ToLowerInvariant, ToUpper, ToUpperInvariant

Gjatë pesë vjetëve të mia të punës në platformën .NET, kam hasur shumë projekte që përdorin krahasimin e string-eve. Gjithashtu kam parë këtë situatë: kishte një zgjidhje Enterprise me shumë projekte, secili prej të cilëve bënte krahasimin e string-eve ndryshe. Por çfarë duhet të përdoret dhe si mund të unifikohet? Në librin CLR via C# nga Richter, lexova se metoda ToUpperInvariant() punon më shpejt se ToLowerInvariant().

Nxjerrje nga libri:

Përformanca në .NET Core

Sigurisht që nuk e besoja dhe vendosa të kryej disa teste në atë kohë në .NET Framework dhe rezultati më befasoi - mbi 15% rritje të performancës. Më pas, në ditën e ardhshme në punë, i tregova këto matje menaxherit tim dhe i dhashë atij qasje në kodin burimor. Pas kësaj, 2 nga 14 projektet u ndryshuan për matjet e reja, dhe duke pasur parasysh se këto dy projekte ekzistonin për të përpunuar tabela të mëdha Excel, rezultati ishte më se i rëndësishëm për produktin.

Gjithashtu, ju paraqes matjet për versionet e ndryshme të .NET Core, në mënyrë që secili prej jush të mund të bëjë zgjedhjen në drejtim të zgjidhjes më optimale. Dhe unë vetëm dëshiroj të shtoj se në kompaninë ku punoj, ne përdorim ToUpper() për krahasimin e string-eve.

Kodi:

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

Përformanca në .NET Core

Përformanca në .NET Core

Në .NET Core 3.0, rritja për çdo këto metoda është ~x2 dhe balancon implementimet mes tyre.

Përformanca në .NET Core

Përformanca në .NET Core

Tier Compilation

Në artikullin e kaluar e përmenda këtë funksionalitet në mënyrë të shkurtër dhe do doja të saktësoja dhe të plotësoja fjalët e mia. Kompilimi në nivele shkurtëzon kohën e nisjes së zgjidhjes tuaj, por ju sakrifikoni faktin që pjesët e kodit tuaj do të kompilohen në një version më të optimizuar në sfond, që mund të çojë në disa shpenzime të vogla. Me ardhjen e .NET Core 3.0, koha e ndërtimit të projekteve me aktivizimin e tier compilation është reduktuar dhe janë rregulluar defektet që ndërlidhen me këtë teknologji. Më parë, kjo teknologji shkaktonte gabime në kërkesat e para në ASP.NET Core dhe ngadalësim gjatë ndërtimit të parë në mënyrën e kompilimit në nivele. Aktualisht, në .NET Core 3.0, ajo është e aktivizuar si parazgjedhje, por mund ta çaktivizoni sipas dëshirës. Nëse jeni në pozita si team-lead, senior, middle ose menaxher departamenti, duhet të kuptoni se zhvillimi i shpejtë i projektit rrit vlerën e ekipit dhe kjo teknologji do t'ju ndihmojë të kurseni kohë si për zhvilluesit ashtu edhe për vetë kohën e punës në projekt.

.NET level up

Rrisni versionin e .NET Framework / .NET Core tuaj. Shumë herë, çdo version i ri ofron një rritje të mëtejshme të performancës dhe shton karakteristika të reja.

Por cila janë përfitimet specifike? Le të shqyrtojmë disa nga to:

  • NĂ« .NET Core 3.0, u prezantuan imazhet R2R, tĂ« cilat do tĂ« lejojnĂ« tĂ« reduktojnĂ« kohĂ«n e nisjes sĂ« aplikacioneve .NET Core.
  • QĂ« nga versioni 2.2, u prezantua Tier Compilation, e cila do tĂ« bĂ«jĂ« qĂ« programuesit tĂ« harxhojnĂ« mĂ« pak kohĂ« pĂ«r tĂ« nisur projektin.
  • MbĂ«shtetje pĂ«r standardet e reja tĂ« .NET Standard.
  • MbĂ«shtetje pĂ«r versionin e ri tĂ« gjuhĂ«s sĂ« programimit.
  • Optimizimi, me çdo version tĂ« ri pĂ«rmirĂ«sohet optimizimi i librarive bazĂ« Collection/Struct/Stream/String/Regex dhe shumĂ« gjĂ«ra tĂ« tjera. NĂ«se kaloni nga .NET Framework nĂ« .NET Core, do tĂ« merrni njĂ« rritje tĂ« madhe tĂ« performancĂ«s nga kuti. PĂ«r shembull, po bashkĂ«ngjisim njĂ« lidhje pĂ«r disa optimizime qĂ« janĂ« shtuar nĂ« .NET Core 3.0: https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core-3-0/

Përformanca në .NET Core

Përfundimi

Kur shkruani kod, duhet të kushtoni vëmendje aspekteve të ndryshme të projektit tuaj dhe të përdorni funksionet e gjuhës suaj të programimit dhe platformës për të arritur rezultatet më të mira. Do të isha i lumtur nëse ndaheni njohuritë tuaja në lidhje me optimizimin në .NET.

Lidhja në github

Burimi: habr.com

Bleni hostim tĂ« besueshĂ«m pĂ«r faqe me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Bleni hostim tĂ« besueshĂ«m pĂ«r faqe me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster