Prestaasje yn .NET Core

Prestaasje yn .NET Core

Prestaasje yn .NET Core

Hoi allegearre! Dit artikel is in samling Best Practices dy't myn kollega's en ik al in lange tiid hawwe brûkt by it wurkjen oan ferskate projekten.

Ynformaasje oer de masine wêrop de berekkeningen waarden útfierd:BenchmarkDotNet = v0.11.5, OS = Windows 10.0.18362
Intel Core i5-8250U CPU 1.60GHz (Kaby Lake R), 1 CPU, 8 logyske en 4 fysike kearnen
.NET Core SDK=3.0.100
[Host]: .NET Core 2.2.7 (CoreCLR 4.6.28008.02, CoreFX 4.6.28008.03), 64bit RyuJIT
Kearn: .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
Kearn: .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT

Job=Core Runtime=Core

ToList vs ToArray en Cycles


Ik wie fan plan om dizze ynformaasje te meitsjen mei de frijlitting fan .NET Core 3.0, mar se sloegen my deroan, ik wol de gloarje fan in oar net stelle en de ynformaasje fan oare minsken kopiearje, dus ik sil gewoan oanwize link nei in goed artikel dêr't de ferliking wurdt beskreaun yn detail.

Ut eigen namme wol ik jo gewoan myn mjittingen en resultaten presintearje. Ik haw se omkearde loops tafoege foar leafhawwers fan 'e "C++-styl" fan skriuwlussen.

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

Prestaasjesnelheden yn .NET Core 2.2 en 3.0 binne hast identyk. Hjir is wat ik koe krije yn .NET Core 3.0:

Prestaasje yn .NET Core

Prestaasje yn .NET Core

Wy kinne konkludearje dat iterative ferwurking fan in Array-kolleksje rapper is troch syn ynterne optimalisaasjes en eksplisite tawizing fan kolleksjegrutte. It is ek de muoite wurdich om te ûnthâlden dat in List-kolleksje syn eigen foardielen hat en jo moatte de juste kolleksje brûke ôfhinklik fan de fereaske berekkeningen. Sels as jo logika skriuwe foar wurkjen mei loops, ferjit net dat dit in gewoane loop is en it is ek ûnder foarbehâld fan mooglike loopoptimalisaasje. In artikel is in lange tiid lyn publisearre op habr: https://habr.com/ru/post/124910/. It is noch altyd relevant en oanrikkemandearre lêzen.

Goaie

In jier lyn wurke ik by in bedriuw oan in legacy-projekt, yn dat projekt wie it normaal om fjildvalidaasje te ferwurkjen troch in try-catch-throw-konstruksje. Ik begriep doe al dat dit ûnsûne saaklike logika wie foar it projekt, dus as it mooglik wie, besocht ik sa'n ûntwerp net te brûken. Mar litte wy útfine wêrom't de oanpak fan it behanneljen fan flaters mei sa'n konstruksje min is. Ik skreau in lytse koade om de twa oanpakken te fergelykjen en benchmarks makke foar elke opsje.

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

De resultaten yn .NET Core 3.0 en Core 2.2 hawwe in ferlykber resultaat (.NET Core 3.0):

Prestaasje yn .NET Core

Prestaasje yn .NET Core

Try catch makket de koade dreger te begripen en fergruttet de útfieringstiid fan jo programma. Mar as jo dizze konstruksje nedich binne, moatte jo dizze rigels koade net ynfoegje dy't net ferwachte wurde om flaters te behanneljen - dit sil de koade makliker te begripen meitsje. Yn feite is it net sasear de ôfhanneling fan útsûnderingen dy't it systeem laden, mar leaver it smiten fan flaters sels troch de throw nije útsûnderingskonstruksje.

Útsûnderings smyt is stadiger as guon klasse dy't sil sammelje de flater yn de fereaske opmaak. As jo ​​​​in formulier of guon gegevens ferwurkje en jo dúdlik witte wat de flater moat wêze, wêrom dan net ferwurkje?

Jo moatte net skriuwe in throw nij útsûndering () konstruksje as dizze situaasje is net útsûnderlik. Omgean en smyt in útsûndering is hiel djoer!!!

ToLower, ToLowerInvariant, ToUpper, ToUpperInvariant

Yn myn 5 jier ûnderfining mei it wurkjen op it .NET-platfoarm bin ik in protte projekten tsjinkaam dy't string matching brûkten. Ik seach ek de folgjende foto: d'r wie ien Enterprise-oplossing mei in protte projekten, wêrfan elk stringfergelikingen oars útfierde. Mar wat moat brûkt wurde en hoe te ferienigjen it? Yn it boek CLR fia C # fan Richter, Ik lês ynformaasje dat de metoade ToUpperInvariant () is flugger as ToLowerInvariant ().

Fraach út it boek:

Prestaasje yn .NET Core

Fansels leaude ik it net en besleat om dan wat tests út te fieren op it .NET Framework en it resultaat skodde my - mear as 15% prestaasjesferheging. Doe't ik de oare moarns op it wurk oankaam, liet ik dizze mjittingen sjen oan myn superieuren en joech se tagong ta de boarnekoade. Hjirnei waarden 2 fan 14 projekten feroare om de nije mjittingen te foldwaan, en yn betinken nommen dat dizze twa projekten bestienen om enoarme Excel-tabellen te ferwurkjen, wie it resultaat mear dan wichtich foar it produkt.

Ik presintearje jo ek mjittingen foar ferskate ferzjes fan .NET Core, sadat elk fan jo in kar meitsje kin foar de meast optimale oplossing. En ik wol gewoan taheakje dat yn it bedriuw dêr't ik wurkje, wy brûke ToUpper () te ferlykje snaren.

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

Prestaasje yn .NET Core

Prestaasje yn .NET Core

Yn .NET Core 3.0 is de ferheging foar elk fan dizze metoaden ~x2 en balansearret de ymplemintaasjes ûnderinoar.

Prestaasje yn .NET Core

Prestaasje yn .NET Core

Tier kompilaasje

Yn myn lêste artikel haw ik dizze funksjonaliteit koart beskreaun, ik wol myn wurden korrigearje en oanfolje. Multi-level kompilaasje fersnelt de opstarttiid fan jo oplossing, mar jo offerje op dat dielen fan jo koade wurde kompilearre yn in mear optimalisearre ferzje op 'e eftergrûn, dy't in lytse overhead kin yntrodusearje. Mei de komst fan NET Core 3.0 is de boutiid foar projekten mei tier-kompilaasje ynskeakele fermindere en bugs ferbûn mei dizze technology binne reparearre. Earder late dizze technology ta flaters yn 'e earste oanfragen yn ASP.NET Core en befriest tidens de earste build yn multi-level kompilaasje modus. It is op it stuit standert ynskeakele yn .NET Core 3.0, mar jo kinne it útskeakelje as jo wolle. As jo ​​​​yn 'e posysje binne fan teamlieder, senior, midden, of jo binne it haad fan in ôfdieling, dan moatte jo begripe dat rappe projektûntwikkeling de wearde fan it team fergruttet en dizze technology sil jo tiid besparje foar beide ûntwikkelders en de tiid fan it projekt sels.

.NET nivo omheech

Upgrade jo .NET Framework / .NET Core ferzje. Faak jout elke nije ferzje ekstra prestaasjeswinsten en foeget nije funksjes ta.

Mar wat binne de foardielen krekt? Litte wy nei guon fan harren sjen:

  • .NET Core 3.0 yntrodusearre R2R-ôfbyldings dy't de opstarttiid fan .NET Core-applikaasjes ferminderje.
  • Mei ferzje 2.2 ferskynde Tier Compilation, troch hokker programmeurs minder tiid sille besteegje oan it lansearjen fan in projekt.
  • Stipe foar nije .NET-standerts.
  • Stipe foar in nije ferzje fan 'e programmeartaal.
  • Optimalisaasje, mei elke nije ferzje ferbetteret de optimalisaasje fan 'e basisbiblioteken Samling / Struct / Stream / String / Regex en folle mear. As jo ​​migrearje fan it .NET Framework nei .NET Core, krije jo in grutte prestaasjesboost út it fak. As foarbyld heakje ik in keppeling ta oan guon fan 'e optimalisaasjes dy't tafoege binne oan .NET Core 3.0: https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core-3-0/

Prestaasje yn .NET Core

konklúzje

By it skriuwen fan koade is it wurdich omtinken te jaan oan ferskate aspekten fan jo projekt en de funksjes fan jo programmeartaal en platfoarm te brûken om it bêste resultaat te berikken. Ik soe bliid wêze as jo jo kennis diele yn ferbân mei optimalisaasje yn .NET.

Keppeling nei github

Boarne: www.habr.com

Add a comment