Ydelse i .NET Core

Ydelse i .NET Core

Ydelse i .NET Core

Hej alle! Denne artikel er en samling af Best Practices, som jeg og mine kolleger har anvendt i lang tid i vores arbejde på forskellige projekter.

Information om den maskine, hvor beregningerne blev udført:BenchmarkDotNet=v0.11.5, OS=Windows 10.0.18362
Intel Core i5-8250U CPU 1.60GHz (Kaby Lake R), 1 CPU, 8 logiske og 4 fysiske kerner
.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 og Cycles


Denne information havde jeg planlagt at udarbejde med udgivelsen af .NET Core 3.0, men jeg blev overhalet. Jeg ønsker ikke at tage andres berømmelse eller kopiere deres information, derfor nævner jeg blot et link til en god artikel, som beskriver sammenligningen i detaljer..

Jeg vil kun præsentere jer for mine målinger og resultater. Jeg har tilføjet omvendte cykler for dem, der elsker "C++ stil" i skrivningen af cykler.

Kode:

public class Bench
    {
        private List _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  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  0; i--)
            {
                total += _array[i];
            }

            return total;
        }
    }

Ydelsen i .NET Core 2.2 og 3.0 er næsten identiske. Her er, hvad jeg har opnået i .NET Core 3.0:

Ydelse i .NET Core

Ydelse i .NET Core

Vi kan konkludere, at cyklisk behandling af en Array-collection er hurtigere på grund af dens interne optimeringer og den eksplicitte størrelsestildeling. Det er også vigtigt at huske, at en List-collection har sine egne fordele, og du bør bruge den rette collection afhængigt af de nødvendige beregninger. Selv når du skriver logikken for cyklusser, må du ikke glemme, at det er en almindelig loop, som også er udsat for potentiel cyklisk optimering. På Habr blev der for længe siden offentliggjort en artikel: https://habr.com/ru/post/124910/. Den er stadig relevant og anbefales til læsning.

Throw

For et år siden arbejdede jeg i et firma på et legacy-projekt, hvor det var normalt at håndtere feltvalidering gennem try-catch-throw konstruktionen. Jeg indså allerede dengang, at det var en usund forretningslogik for projektet, så jeg forsøgte at undgå denne konstruktion, når det var muligt. Men lad os se nærmere på, hvorfor det er en dårlig idé at håndtere fejl på denne måde. Jeg skrev en lille kode til at sammenligne to tilgange og tog 'benchmarks' for hver variant.

Kode:

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

Resultaterne i .NET Core 3.0 og Core 2.2 viser et lignende resultat (.NET Core 3.0):

Ydelse i .NET Core

Ydelse i .NET Core

Try catch gør koden sværere at forstå og øger udførelsestiden for dit program. Men hvis du har brug for denne konstruktion, skal du undgå at indsætte de kodestykker, som ikke forventer fejlbehandling — det vil lette forståelsen af koden. Faktisk belaster behandlingen af undtagelser ikke systemet så meget som selve kasteren af fejl gennem konstruktionen throw new Exception.

At kaste undtagelser er langsommere end en hvilken som helst klasse, der samler fejlen i det ønskede format. Hvis du behandler en formular eller nogle data og tydeligt ved, hvilken fejl der skal være, hvorfor så ikke håndtere dem?

Det er ikke nødvendigt at skrive konstruktionen throw new Exception(), hvis denne situation ikke er exceptionel. Håndtering og kaste af undtagelser er ekstremt dyrt!!!

ToLower, ToLowerInvariant, ToUpper, ToUpperInvariant

I min 5-årige erfaring med .NET-platformen har jeg set mange projekter, der brugte strængsammenligning. Jeg har også set følgende situation: der var en Enterprise-løsning med mange projekter, hvor hver udførte strængsammenligning forskelligt. Men hvad skal man bruge, og hvordan kan det standardiseres? I bogen CLR via C# af Richter læste jeg, at metoden ToUpperInvariant() kører hurtigere end ToLowerInvariant().

Uddrag fra bogen:

Ydelse i .NET Core

Selvfølgelig troede jeg ikke på det og besluttede at foretage nogle tests dengang på .NET Framework, og resultatet chokerede mig — mere end 15% forbedring i ydeevne. Næste morgen på arbejdet viste jeg mine målinger til ledelsen og gav dem adgang til kildeteksten. Efter dette blev 2 ud af 14 projekter ændret for de nye målinger, og i betragtning af, at disse to projekter eksisterede for at håndtere enorme excel-tabeller, var resultatet mere end betydeligt for produktet.

Jeg præsenterer også målinger for forskellige versioner af .NET Core, så hver af jer kan vælge den mest optimerede løsning. Og jeg vil blot tilføje, at i firmaet, hvor jeg arbejder, bruger vi ToUpper() til strængsammenligning.

Kode:

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

Ydelse i .NET Core

Ydelse i .NET Core

I .NET Core 3.0 er forbedringen for hver af disse metoder ~x2 og balancerer implementeringerne imellem.

Ydelse i .NET Core

Ydelse i .NET Core

Tier Compilation

I min tidligere artikel beskrev jeg denne funktion kort, men jeg vil gerne rette og supplere mine ord. Multi-level compilation fremskynder opstartstiden for din løsning, men du ofrer det faktum, at dele af din kode vil blive kompilering i en mere optimeret version i baggrunden, hvilket kan medføre små overheadomkostninger. Med ankomsten af .NET Core 3.0 er tiden til bygning af projekter med aktiveret tier compilation blevet reduceret, og der er rettet fejl relateret til denne teknologi. Tidligere førte denne teknologi til fejl ved første forespørgsler i ASP.NET Core og til hængning ved første bygning i multi-level kompilationsmåde. I øjeblikket er det i .NET Core 3.0 aktiveret som standard, men du kan deaktivere det efter behov. Hvis du er team-lead, senior, middle eller leder af en afdeling, bør du forstå, at hurtigere udvikling af projekter øger teamets værdi, og denne teknologi vil spare tid for både udviklere og det samlede arbejdstid i projektet.

.NET niveau op

Opgrader din .NET Framework / .NET Core. Ofte giver hver ny version et ekstra boost til ydeevnen og tilføjer nye funktioner.

Men hvilke fordele præcist? Lad os se på nogle af dem:

  • I .NET Core 3.0 er der kommet R2R billeder, som vil reducere opstartstiden for .NET Core applikationer.
  • Fra version 2.2 er der kommet Tier Compilation, som gør, at programmører vil bruge mindre tid på at starte projektet.
  • Understøttelse af nye standarder i .NET Standard.
  • Understøttelse af den nye version af programmeringssproget.
  • Optimering, hver nye version forbedrer optimeringen af basisbiblioteker som Collection/Struct/Stream/String/Regex og meget mere. Hvis du skifter fra .NET Framework til .NET Core, vil du få en betydelig ydeevneforbedring lige ud af boksen. Som eksempel vedhæfter jeg et link til nogle af de optimeringer, der blev tilføjet i .NET Core 3.0: https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core-3-0/

Ydelse i .NET Core

Konklusion

Når du skriver kode, er det vigtigt at fokusere på forskellige aspekter af dit projekt og bruge funktioner på dit programmeringssprog og platformen for at opnå det bedste resultat. Jeg vil være glad, hvis du deler dine indsigter vedrørende optimering i .NET.

Link til github

Kilde: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster