Performanca në .NET Core

Performanca në .NET Core

Performanca në .NET Core

Pershendetje te gjitheve! Ky artikull është një koleksion i praktikave më të mira që kolegët e mi dhe unë i kemi përdorur për një kohë të gjatë kur punojmë në projekte të ndryshme.

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

Puna=Koha e ekzekutimit bazë=Bërthama

ToList vs ToArray dhe Ciklet


Kam planifikuar ta përgatis këtë informacion me lëshimin e .NET Core 3.0, por ata më rrahën, nuk dua të vjedh lavdinë e dikujt tjetër dhe të kopjoj informacionin e njerëzve të tjerë, kështu që thjesht do të theksoj lidhje me një artikull të mirë ku krahasimi përshkruhet në detaje.

Në emrin tim, thjesht dua t'ju prezantoj matjet dhe rezultatet e mia; u shtova sythe të kundërta për dashamirët e "stilit C++" të sytheve të shkrimit.

Code:

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ësitë e performancës në .NET Core 2.2 dhe 3.0 janë pothuajse identike. Ja çfarë arrita të marr në .NET Core 3.0:

Performanca në .NET Core

Performanca në .NET Core

Mund të konkludojmë se përpunimi përsëritës i një koleksioni Array është më i shpejtë për shkak të optimizimeve të tij të brendshme dhe alokimit të qartë të madhësisë së koleksionit. Vlen gjithashtu të kujtohet se një koleksion Lista ka avantazhet e veta dhe ju duhet të përdorni koleksionin e duhur në varësi të llogaritjeve të kërkuara. Edhe nëse shkruani logjikë për të punuar me sythe, mos harroni se ky është një lak i zakonshëm dhe gjithashtu i nënshtrohet optimizimit të mundshëm të lakut. Një artikull u botua në habr shumë kohë më parë: https://habr.com/ru/post/124910/. Është ende relevante dhe rekomandohet të lexohet.

Hedh

Një vit më parë, unë punova në një kompani në një projekt të trashëguar, në atë projekt ishte normale të përpunohej vërtetimi në terren përmes një konstrukti try-catch-through. E kuptova që atëherë se kjo ishte logjikë e pashëndetshme e biznesit për projektin, kështu që sa herë që ishte e mundur, përpiqesha të mos përdorja një dizajn të tillë. Por le të kuptojmë pse qasja për trajtimin e gabimeve me një ndërtim të tillë është e keqe. Shkrova një kod të vogël për të krahasuar dy qasjet dhe bëra standarde për secilin opsion.

Code:

        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ë një rezultat të ngjashëm (.NET Core 3.0):

Performanca në .NET Core

Performanca në .NET Core

Provoni kapjen e bën kodin më të vështirë për t'u kuptuar dhe rrit kohën e ekzekutimit të programit tuaj. Por nëse keni nevojë për këtë ndërtim, nuk duhet të futni ato rreshta kodi që nuk pritet të trajtojnë gabimet - kjo do ta bëjë kodin më të lehtë për t'u kuptuar. Në fakt, nuk është aq shumë trajtimi i përjashtimeve që ngarkon sistemin, por më tepër hedhja e vetë gabimeve përmes konstruksionit të hedhjes së re të përjashtimit.

Hedhja e përjashtimeve është më e ngadalshme se disa klasa që do të mbledhin gabimin në formatin e kërkuar. Nëse jeni duke përpunuar një formular ose disa të dhëna dhe e dini qartë se cili duhet të jetë gabimi, pse të mos e përpunoni?

Ju nuk duhet të shkruani një konstruksion të ri të hedhjes Exception() nëse kjo situatë nuk është e jashtëzakonshme. Trajtimi dhe hedhja e një përjashtimi është shumë e shtrenjtë!!!

ToLower, ToLowerInvariant, ToUpper, ToUpperInvariant

Gjatë përvojës sime 5 vjeçare duke punuar në platformën .NET, kam hasur në shumë projekte që përdornin përputhjen e vargjeve. Pashë gjithashtu foton e mëposhtme: kishte një zgjidhje të Ndërmarrjes me shumë projekte, secila prej të cilave kryente krahasime të vargjeve në mënyra të ndryshme. Por çfarë duhet përdorur dhe si ta unifikojmë atë? Në librin CLR via C# nga Richter, lexova informacione se metoda ToUpperInvariant() është më e shpejtë se ToLowerInvariant().

Fragment nga libri:

Performanca në .NET Core

Sigurisht, nuk e besova dhe vendosa të bëj disa teste në .NET Framework dhe rezultati më tronditi - më shumë se 15% rritje e performancës. Më pas, me të mbërritur në punë të nesërmen në mëngjes, ua tregova këto matje eprorëve të mi dhe u dhashë akses në kodin burimor. Pas kësaj, 2 nga 14 projekte u ndryshuan për të akomoduar matjet e reja, dhe duke pasur parasysh që këto dy projekte ekzistonin për të përpunuar tabela të mëdha Excel, rezultati ishte më se domethënës për produktin.

Ju prezantoj edhe matjet për versione të ndryshme të .NET Core, në mënyrë që secili prej jush të bëjë një zgjedhje drejt zgjidhjes më optimale. Dhe thjesht dua të shtoj se në kompaninë ku punoj, ne përdorim ToUpper() për të krahasuar vargjet.

Code:

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

Performanca në .NET Core

Performanca në .NET Core

Në .NET Core 3.0, rritja për secilën nga këto metoda është ~x2 dhe balancon implementimet ndërmjet tyre.

Performanca në .NET Core

Performanca në .NET Core

Përpilimi i nivelit

Në artikullin tim të fundit që e përshkrova shkurtimisht këtë funksion, do të doja të korrigjoja dhe plotësoja fjalët e mia. Kompilimi me shumë nivele përshpejton kohën e fillimit të zgjidhjes suaj, por ju sakrifikoni që pjesë të kodit tuaj do të përpilohen në një version më të optimizuar në sfond, i cili mund të sjellë një shpenzim të vogël. Me ardhjen e NET Core 3.0, koha e ndërtimit për projektet me përpilimin e niveleve të aktivizuar është zvogëluar dhe gabimet që lidhen me këtë teknologji janë rregulluar. Më parë, kjo teknologji çoi në gabime në kërkesat e para në ASP.NET Core dhe ngrinte gjatë ndërtimit të parë në modalitetin e përpilimit me shumë nivele. Aktualisht është aktivizuar si parazgjedhje në .NET Core 3.0, por mund ta çaktivizoni nëse dëshironi. Nëse jeni në pozicionin e drejtuesit të ekipit, të lartë, të mesëm ose jeni drejtues i një departamenti, atëherë duhet të kuptoni se zhvillimi i shpejtë i projektit rrit vlerën e ekipit dhe kjo teknologji do t'ju lejojë të kurseni kohë për të dy zhvilluesit. dhe vetë kohën e projektit.

Ngritja e nivelit .NET

Përmirësoni versionin tuaj .NET Framework / .NET Core. Shpesh, çdo version i ri siguron përfitime shtesë të performancës dhe shton veçori të reja.

Por cilat janë konkretisht përfitimet? Le të shohim disa prej tyre:

  • .NET Core 3.0 prezantoi imazhe R2R që do të reduktojnë kohën e fillimit të aplikacioneve .NET Core.
  • Me versionin 2.2, u shfaq përpilimi i nivelit, falë të cilit programuesit do të shpenzojnë më pak kohë për të nisur një projekt.
  • Mbështetje për standardet e reja .NET.
  • Mbështetje për një version të ri të gjuhës së programimit.
  • Optimizimi, me çdo version të ri përmirësohet optimizimi i bibliotekave bazë Collection/Struct/Stream/String/Regex dhe shumë më tepër. Nëse po migroni nga .NET Framework në .NET Core, do të merrni një rritje të madhe të performancës jashtë kutisë. Si shembull, unë bashkangjit një lidhje me disa nga optimizimet që janë shtuar në .NET Core 3.0: https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core-3-0/

Performanca në .NET Core

Përfundim

Kur shkruani kodin, ia vlen t'i kushtoni vëmendje aspekteve të ndryshme të projektit tuaj dhe të përdorni veçoritë e gjuhës dhe platformës së programimit për të arritur rezultatin më të mirë. Do të isha i lumtur nëse ndani njohuritë tuaja në lidhje me optimizimin në .NET.

Lidhje me github

Burimi: www.habr.com

Shto një koment