Prestaties in .NET Core

Prestaties in .NET Core

Prestaties in .NET Core

Hallo allemaal! Dit artikel is een verzameling van Best Practices die ik en mijn collega's al lange tijd toepassen in verschillende projecten.

Informatie over de machine waarop de berekeningen zijn uitgevoerd:BenchmarkDotNet=v0.11.5, OS=Windows 10.0.18362
Intel Core i5-8250U CPU 1.60GHz (Kaby Lake R), 1 CPU, 8 logische en 4 fysieke cores
.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 versus ToArray en Lussen


Ik had deze informatie willen voorbereiden met de release van .NET Core 3.0, maar ik ben overtroffen, ik wil geen glorie van iemand anders stelen en wil geen informatie kopiƫren, daarom geef ik gewoon een link naar een goed artikel, waar de vergelijking gedetailleerd is beschreven.

Ik wil jullie alleen mijn metingen en resultaten presenteren, ik heb hieraan achterwaartse lussen toegevoegd voor de liefhebbers van de "C++ stijl" van lussen schrijven.

Code:

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

De snelheid van .NET Core 2.2 en 3.0 is bijna identiek. Dit is wat ik heb kunnen verkrijgen in .NET Core 3.0:

Prestaties in .NET Core

Prestaties in .NET Core

We kunnen concluderen dat het cyclisch verwerken van een Array-collectie sneller is, dankzij de interne optimalisaties en de expliciete grootte van de collectie. Ook moet worden opgemerkt dat de List-collectie zijn eigen voordelen heeft en dat je de juiste collectie moet gebruiken, afhankelijk van de benodigde berekeningen. Zelfs als je logica schrijft voor loops, moet je niet vergeten dat dit een gewone loop is en ook onderhevig is aan mogelijke optimalisatie. Er is een artikel op habr dat al een tijdje geleden is verschenen: https://habr.com/ru/post/124910/. Het is nog steeds actueel en wordt aanbevolen om te lezen.

Throw

Een jaar geleden werkte ik bij een bedrijf aan een legacy-project, waarin het normaal was om veldvalidatie te verwerken met de try-catch-throw-structuur. Ik begreep toen al dat dit een ongezonde businesslogica was, dus probeerde ik waar mogelijk deze structuur te vermijden. Maar laten we eens kijken waarom het problematisch is om fouten op deze manier te verwerken. Ik heb een kleine code geschreven om twee benaderingen te vergelijken en benchmarks uitgevoerd voor elke optie.

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 in .NET Core 3.0 en Core 2.2 zijn vergelijkbaar (.NET Core 3.0):

Prestaties in .NET Core

Prestaties in .NET Core

Try catch maakt het begrijpen van de code moeilijker en verhoogt de uitvoeringstijd van je programma. Maar als je deze constructie nodig hebt, moet je de regels code die geen foutverwerking vereisen, niet opnemen — dit vergemakkelijkt het begrip van de code. In feite is het niet zozeer de verwerking van uitzonderingen die het systeem belast, maar eerder het opwerpen van de fouten zelf via de constructie throw new Exception.

Het opwerpen van uitzonderingen werkt trager dan een klasse die de fout in het juiste formaat verzamelt. Als je een formulier of gegevens verwerkt en precies weet welke fout er zou moeten zijn, waarom zou je ze dan niet verwerken?

Je moet geen constructie zoals throw new Exception() schrijven als deze situatie geen uitzondering is. Het afhandelen en uitwerpen van uitzonderingen is enorm kostbaar!!!

ToLower, ToLowerInvariant, ToUpper, ToUpperInvariant

In mijn 5-jarige ervaring met het .NET-platform heb ik veel projecten gezien die stringvergelijkingen gebruikten. Ook heb ik het volgende gezien: er was ƩƩn Enterprise-oplossing met veel projecten, elk gebruikten een andere aanpak voor stringvergelijkingen. Wat moet je gebruiken en hoe kun je dat standaardiseren? In het boek CLR via C# van Richter las ik dat de methode ToUpperInvariant() sneller werkt dan ToLowerInvariant().

Uittreksel uit het boek:

Prestaties in .NET Core

Natuurlijk geloofde ik het niet en besloot ik wat tests uit te voeren op .NET Framework en de resultaten schokten me — meer dan 15% prestatieverbetering. De volgende ochtend op het werk toonde ik deze metingen aan mijn leidinggevenden en gaf hen toegang tot de broncode. Hierna werden 2 van de 14 projecten aangepast voor de nieuwe metingen, en aangezien deze twee projecten bedoeld waren voor het verwerken van enorme Excel-tabellen, was het resultaat zeer significant voor het product.

Daarnaast presenteer ik metingen voor verschillende versies van .NET Core, zodat ieder van jullie kan kiezen voor de meest optimale oplossing. Ik wil eraan toevoegen dat we in het bedrijf waar ik werk ToUpper() gebruiken voor stringvergelijkingen.

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

Prestaties in .NET Core

Prestaties in .NET Core

In .NET Core 3.0 is de verbetering voor elk van deze methoden ~x2 en balanceert de implementaties met elkaar.

Prestaties in .NET Core

Prestaties in .NET Core

Tier Compilation

In mijn vorige artikel gaf ik een korte beschrijving van deze functionaliteit, maar ik wil mijn woorden corrigeren en aanvullen. Meerdere niveaus van compilatie versnellen de opstarttijd van uw oplossing, maar u offert op dat delen van uw code op de achtergrond worden gecompileerd naar een meer geoptimaliseerde versie, wat kan leiden tot kleine overheadkosten. Met de komst van .NET Core 3.0 is de bouwtijd van projecten met ingeschakelde tiercompilatie verminderd en zijn de bugs die met deze technologie verband houden opgelost. Eerder leidde deze technologie tot fouten bij de eerste verzoeken in ASP.NET Core en tot vastlopen bij de eerste compilatie in de modus van meerdere niveaus van compilatie. Momenteel is het in .NET Core 3.0 standaard ingeschakeld, maar u kunt het naar wens uitschakelen. Als u werkt als teamleider, senior, middle of als afdelingleider, moet u begrijpen dat snelle projectontwikkeling de waarde van het team verhoogt en dat deze technologie u in staat stelt tijd te besparen, zowel voor ontwikkelaars als voor de projectwerkzaamheden.

.NET niveau omhoog

Verhoog de versie van uw .NET Framework / .NET Core. Vaak biedt elke nieuwe versie een extra prestatieverbetering en voegt nieuwe functies toe.

Maar wat zijn de specifieke voordelen? Laten we enkele daarvan bekijken:

  • In .NET Core 3.0 zijn er R2R-afbeeldingen geĆÆntroduceerd, die de opstarttijd van .NET Core-toepassingen zullen verlagen.
  • Met versie 2.2 is Tier Compilation geĆÆntroduceerd, waardoor programmeurs minder tijd moeten besteden aan het opstarten van hun projecten.
  • Ondersteuning voor nieuwe normen van .NET Standard.
  • Ondersteuning voor de nieuwe versie van de programmeertaal.
  • Optimalisatie; met elke nieuwe versie worden de basisbibliotheken Collection/Struct/Stream/String/Regex en nog veel meer geoptimaliseerd. Als u overstapt van .NET Framework naar .NET Core, krijgt u een aanzienlijke prestatieverbetering uit de doos. Ter illustratie voeg ik een link toe naar een deel van de optimalisaties die zijn toegevoegd in .NET Core 3.0: https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core-3-0/

Prestaties in .NET Core

Conclusie

Bij het schrijven van code is het belangrijk om aandacht te besteden aan verschillende aspecten van uw project en gebruik te maken van de functies van uw programmeertaal en platform om het beste resultaat te bereiken. Ik zou het op prijs stellen als u uw kennis over optimalisatie in .NET met mij deelt.

Link naar github

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers šŸ”„ Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster