Prestanda i .NET Core

Prestanda i .NET Core

Prestanda i .NET Core

Hej alla! Denna artikel Àr en samling av bÀsta praxis som jag och mina kollegor har tillÀmpat under lÄng tid nÀr vi arbetar med olika projekt.

Information om maskinen dÀr berÀkningarna utfördes:BenchmarkDotNet=v0.11.5, OS=Windows 10.0.18362
Intel Core i5-8250U CPU 1.60GHz (Kaby Lake R), 1 CPU, 8 logiska och 4 fysiska kÀrnor
.NET Core SDK=3.0.100
[Host]: .NET Core 2.2.7 (CoreCLR 4.6.28008.02, CoreFX 4.6.28008.03), 64bit RyuJIT
KĂ€rna: .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
KĂ€rna: .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT

Job=Core Runtime=Core

ToList vs ToArray och Cykler


Denna information hade jag planerat att förbereda samtidigt som .NET Core 3.0 slÀpptes, men jag blev översprungen. Jag vill inte ta nÄgon annans Àra eller kopiera deras information, sÄ jag kommer helt enkelt att nÀmna en lÀnk till en bra artikel dÀr en detaljerad jÀmförelse görs.

FrÄn mig vill jag bara presentera mina mÀtningar och resultat. Jag har lagt till omvÀnda cykler för dem som gillar "C++-stilen" för att skriva cykler.

Kod:

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

Prestandan i .NET Core 2.2 och 3.0 Àr nÀstan identisk. HÀr Àr vad jag lyckades fÄ i .NET Core 3.0:

Prestanda i .NET Core

Prestanda i .NET Core

Vi kan dra slutsatsen att cyklisk behandling av en Array-samling Ă€r snabbare tack vare dess interna optimeringar och tydliga storleksallokering. Det Ă€r ocksĂ„ vĂ€rt att notera att List-samlingen har sina egna fördelar, och du bör anvĂ€nda den samling som passar bĂ€st beroende pĂ„ de önskade berĂ€kningarna. Även om du skriver logiken för loopar, bör du inte glömma att det Ă€r en vanlig loop som ocksĂ„ kan optimeras. PĂ„ Habr har det för lĂ€nge sedan publicerats en artikel: https://habr.com/ru/post/124910/. Den Ă€r fortfarande aktuell och rekommenderas för lĂ€sning.

Throw

För ett Är sedan arbetade jag med ett företag pÄ ett legacy-projekt dÀr det var normalt att hantera fÀltvalidering med en try-catch-throw-konstruktion. Jag insÄg redan dÄ att detta var en ohÀlsosam affÀrslogik för projektet, sÄ jag försökte undvika att anvÀnda en sÄdan konstruktion nÀr det var möjligt. Men lÄt oss gÄ igenom varför det Àr dÄligt att hantera fel med en sÄdan konstruktion. Jag skrev en liten kod för att jÀmföra de tvÄ metoderna och tog bÀnktester pÄ varje alternativ.

Kod:

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

Resultaten i .NET Core 3.0 och Core 2.2 visar liknande resultat (.NET Core 3.0):

Prestanda i .NET Core

Prestanda i .NET Core

Try-catch gör koden svĂ„rare att förstĂ„ och ökar körningstiden för ditt program. Men om du behöver denna konstruktion, bör du inte inkludera koder dĂ€r du inte förvĂ€ntar dig felhantering – detta underlĂ€ttar förstĂ„elsen av koden. Faktum Ă€r att det inte Ă€r hanteringen av undantag som belastar systemet, utan snarare att kastar undantagen med hjĂ€lp av konstruktionen throw new Exception.

Att kasta undantag Àr lÄngsammare Àn vilken klass som helst som samlar in felen i det format som behövs. Om du hanterar en form eller nÄgra data och vet exakt vilken felaktighet som uppstÄr, varför inte hantera dem?

Du bör inte skriva konstruktionen throw new Exception() om den situationen inte Àr exceptionell. Att hantera och kasta undantag Àr otroligt kostsamt!!!

ToLower, ToLowerInvariant, ToUpper, ToUpperInvariant

Under mina 5 Är av arbete pÄ .NET-plattformen har jag stött pÄ mÄnga projekt som anvÀnde strÀngjÀmförelse. Jag har ocksÄ sett följande bild: det fanns en Enterprise-lösning med mÄnga projekt, var och en jÀmförde strÀngar pÄ olika sÀtt. Men vad ska man anvÀnda och hur kan man enhetliggöra det? I boken CLR via C# av Richter lÀste jag att metoden ToUpperInvariant() fungerar snabbare Àn ToLowerInvariant().

Utdrag ur boken:

Prestanda i .NET Core

SjĂ€lvklart trodde jag inte pĂ„ det och beslutade att göra nĂ„gra tester pĂ„ den dĂ„varande .NET Framework, och resultatet chockade mig — över 15% ökning av prestandan. NĂ€sta morgon pĂ„ jobbet visade jag mĂ€tdata för min chef och gav dem tillgĂ„ng till kĂ€llkoden. Efter det Ă€ndrades 2 av 14 projekt för att passa de nya mĂ€tningarna, och med tanke pĂ„ att dessa tvĂ„ projekt fanns för att hantera stora Excel-tabeller var resultatet mer Ă€n betydelsefullt för produkten.

HÀr Àr ocksÄ mÀtningar för olika versioner av .NET Core, sÄ att var och en av er kan vÀlja den mest optimala lösningen. Och jag vill bara tillÀgga att pÄ företaget dÀr jag arbetar anvÀnder vi ToUpper() för strÀngjÀmförelse.

Kod:

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

Prestanda i .NET Core

Prestanda i .NET Core

.NET Core 3.0 uppvisar en ökning för var och en av dessa metoder ~x2 och balanserar implementeringarna mellan sig.

Prestanda i .NET Core

Prestanda i .NET Core

Tier Compilation

I den senaste artikeln beskrev jag denna funktion kort, och jag skulle vilja korrigera och komplettera mina ord. Flerlagerskompilering förkortar uppstartstiden för din lösning, men du offrar att delar av din kod kommer att kompileras till en mer optimerad version i bakgrunden, vilket kan leda till mindre överhÀdningar. Med ankomsten av .NET Core 3.0 har byggets tid minskat för projekt med aktiverad tier compilation, och buggar relaterade till denna teknik har ÄtgÀrdats. Tidigare ledde denna teknik till fel vid de första förfrÄgningarna i ASP.NET Core och kraschade vid första bygget i flerlagerskompilering. För nÀrvarande Àr det aktiverat som standard i .NET Core 3.0, men du kan inaktivera det om du vill. Om du Àr teamledare, senior, medel eller avdelningschef, mÄste du förstÄ att snabb utveckling av projekt ökar teamets vÀrde, och denna teknik kommer att hjÀlpa dig spara tid för bÄde utvecklarna och sjÀlva projektets arbete.

.NET nivÄ upp

Höj din version av .NET Framework / .NET Core. Ofta ger varje ny version en ytterligare prestandaökning och lÀgger till nya funktioner.

Men vilka fördelar Àr det egentligen? LÄt oss titta pÄ nÄgra av dem:

  • I .NET Core 3.0 introducerades R2R-bilder, som kommer att minska uppstartstiden för .NET Core-applikationer.
  • FrĂ„n version 2.2 introducerades Tier Compilation, vilket gör att programmerare kommer att spendera mindre tid pĂ„ att starta projektet.
  • Stöd för nya standarder i .NET Standard.
  • Stöd för den nya versionen av programmeringssprĂ„ket.
  • Optimering, med varje ny version förbĂ€ttras optimeringen av grundlĂ€ggande bibliotek som Collection/Struct/Stream/String/Regex och mycket mer. Om du gĂ„r frĂ„n .NET Framework till .NET Core, fĂ„r du en stor prestandaökning direkt. Som exempel bifogar jag en lĂ€nk till de optimeringar som lagts till i .NET Core 3.0: https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core-3-0/

Prestanda i .NET Core

Slutsats

NÀr du skriver kod Àr det viktigt att uppmÀrksamma olika aspekter av ditt projekt och att anvÀnda funktioner i ditt programmeringssprÄk och plattform för att uppnÄ bÀsta resultat. Jag skulle vara glad om du delar med dig av dina kunskaper om optimering i .NET.

LĂ€nk till github

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster