Pagganap sa .NET Core

Pagganap sa .NET Core

Pagganap sa .NET Core

Kamusta kayong lahat! Ang artikulong ito ay isang koleksyon ng Mga Pinakamahusay na Kasanayan na matagal na naming ginagamit ng aking mga kasamahan kapag gumagawa ng iba't ibang proyekto.

Impormasyon tungkol sa makina kung saan isinagawa ang mga kalkulasyon:BenchmarkDotNet=v0.11.5, OS=Windows 10.0.18362
Intel Core i5-8250U CPU 1.60GHz (Kaby Lake R), 1 CPU, 8 logical at 4 na pisikal na core
.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 and Cycles


Pinlano kong ihanda ang impormasyong ito sa paglabas ng .NET Core 3.0, ngunit natalo nila ako, ayaw kong magnakaw ng kaluwalhatian ng ibang tao at kopyahin ang impormasyon ng ibang tao, kaya ituturo ko lang link sa isang magandang artikulo kung saan ang paghahambing ay inilarawan nang detalyado.

Sa sarili kong ngalan, gusto ko lang ipakita sa iyo ang aking mga sukat at resulta; Nagdagdag ako ng mga reverse loop sa kanila para sa mga mahilig sa "C++ style" ng writing loops.

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

Ang bilis ng pagganap sa .NET Core 2.2 at 3.0 ay halos magkapareho. Narito ang nakuha ko sa .NET Core 3.0:

Pagganap sa .NET Core

Pagganap sa .NET Core

Maaari naming tapusin na ang umuulit na pagproseso ng isang koleksyon ng Array ay mas mabilis dahil sa mga panloob na pag-optimize nito at tahasang paglalaan ng laki ng koleksyon. Dapat ding tandaan na ang isang koleksyon ng Listahan ay may sariling mga pakinabang at dapat mong gamitin ang tamang koleksyon depende sa mga kinakailangang kalkulasyon. Kahit na sumulat ka ng lohika para sa pagtatrabaho sa mga loop, huwag kalimutan na ito ay isang ordinaryong loop at napapailalim din ito sa posibleng pag-optimize ng loop. Ang isang artikulo ay nai-publish sa habr medyo matagal na ang nakalipas: https://habr.com/ru/post/124910/. May kaugnayan pa rin ito at inirerekomendang basahin.

Itapon

Isang taon na ang nakalipas, nagtrabaho ako sa isang kumpanya sa isang legacy na proyekto, sa proyektong iyon ay normal na iproseso ang pagpapatunay ng field sa pamamagitan ng isang try-catch-throw construct. Naunawaan ko na noon na ito ay hindi malusog na lohika ng negosyo para sa proyekto, kaya hangga't maaari sinubukan kong huwag gumamit ng gayong disenyo. Ngunit alamin natin kung bakit masama ang diskarte sa paghawak ng mga error sa naturang konstruksiyon. Sumulat ako ng isang maliit na code upang ihambing ang dalawang diskarte at gumawa ng mga benchmark para sa bawat opsyon.

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

Ang mga resulta sa .NET Core 3.0 at Core 2.2 ay may katulad na resulta (.NET Core 3.0):

Pagganap sa .NET Core

Pagganap sa .NET Core

Ang try catch ay ginagawang mas mahirap maunawaan ang code at pinapataas ang oras ng pagpapatupad ng iyong programa. Ngunit kung kailangan mo ang construction na ito, hindi mo dapat ipasok ang mga linyang iyon ng code na hindi inaasahang makakahawak ng mga error - gagawin nitong mas madaling maunawaan ang code. Sa katunayan, hindi ang pangangasiwa ng mga eksepsiyon ang naglo-load sa system, ngunit sa halip ang paghahagis ng mga error mismo sa pamamagitan ng throw new Exception construct.

Ang paghahagis ng mga exception ay mas mabagal kaysa sa ilang klase na mangongolekta ng error sa kinakailangang format. Kung nagpoproseso ka ng isang form o ilang data at malinaw mong alam kung ano ang dapat na error, bakit hindi mo ito iproseso?

Hindi ka dapat magsulat ng throw new Exception() construct kung hindi kakaiba ang sitwasyong ito. Ang paghawak at paghahagis ng exception ay napakamahal!!!

ToLower, ToLowerInvariant, ToUpper, ToUpperInvariant

Sa loob ng 5 taong karanasan ko sa pagtatrabaho sa .NET platform, marami akong nakitang proyekto na gumamit ng pagtutugma ng string. Nakita ko rin ang sumusunod na larawan: mayroong isang Enterprise solution na may maraming proyekto, na ang bawat isa ay nagsagawa ng mga paghahambing ng string nang iba. Ngunit ano ang dapat gamitin at paano ito pag-isahin? Sa aklat na CLR sa pamamagitan ng C# ni Richter, nabasa ko ang impormasyon na ang ToUpperInvariant() na pamamaraan ay mas mabilis kaysa sa ToLowerInvariant().

Sipi mula sa aklat:

Pagganap sa .NET Core

Siyempre, hindi ako naniwala at nagpasya akong magpatakbo ng ilang pagsubok noon sa .NET Framework at nagulat ako sa resulta - higit sa 15% na pagtaas ng performance. Pagkatapos, pagdating sa trabaho kinaumagahan, ipinakita ko ang mga sukat na ito sa aking mga superyor at binigyan sila ng access sa source code. Pagkatapos nito, 2 sa 14 na proyekto ang binago upang matugunan ang mga bagong sukat, at kung isasaalang-alang na ang dalawang proyektong ito ay umiral upang iproseso ang malalaking talahanayan ng Excel, ang resulta ay higit na makabuluhan para sa produkto.

Nagpapakita rin ako sa iyo ng mga sukat para sa iba't ibang bersyon ng .NET Core, upang ang bawat isa sa inyo ay makakapili sa pinakamainam na solusyon. At gusto ko lang idagdag na sa kumpanyang pinagtatrabahuhan ko, ginagamit namin ang ToUpper() para ihambing ang mga string.

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

Pagganap sa .NET Core

Pagganap sa .NET Core

Sa .NET Core 3.0, ang pagtaas para sa bawat isa sa mga pamamaraang ito ay ~x2 at binabalanse ang mga pagpapatupad sa kanilang mga sarili.

Pagganap sa .NET Core

Pagganap sa .NET Core

Tier Compilation

Sa aking huling artikulo ay inilarawan ko nang maikli ang pagpapaandar na ito, nais kong iwasto at dagdagan ang aking mga salita. Pinapabilis ng multi-level compilation ang oras ng pagsisimula ng iyong solusyon, ngunit isinakripisyo mo na ang mga bahagi ng iyong code ay isasama sa isang mas na-optimize na bersyon sa background, na maaaring magpakilala ng maliit na overhead. Sa pagdating ng NET Core 3.0, nabawasan ang oras ng pagbuo para sa mga proyektong may naka-enable na tier compilation at naayos na ang mga bug na nauugnay sa teknolohiyang ito. Dati, ang teknolohiyang ito ay humantong sa mga error sa mga unang kahilingan sa ASP.NET Core at nag-freeze sa unang pagbuo sa multi-level na compilation mode. Ito ay kasalukuyang pinagana bilang default sa .NET Core 3.0, ngunit maaari mo itong i-disable kung gusto mo. Kung ikaw ay nasa posisyon ng team-lead, senior, middle, o ikaw ang pinuno ng isang departamento, dapat mong maunawaan na ang mabilis na pagbuo ng proyekto ay nagpapataas ng halaga ng koponan at ang teknolohiyang ito ay magbibigay-daan sa iyong makatipid ng oras para sa parehong mga developer at ang oras ng proyekto mismo.

.NET level up

I-upgrade ang iyong .NET Framework / .NET Core na bersyon. Kadalasan, ang bawat bagong bersyon ay nagbibigay ng karagdagang performance gains at nagdaragdag ng mga bagong feature.

Ngunit ano nga ba ang mga benepisyo? Tingnan natin ang ilan sa kanila:

  • Ipinakilala ng .NET Core 3.0 ang mga R2R na larawan na magbabawas sa oras ng pagsisimula ng mga .NET Core na application.
  • Sa bersyon 2.2, lumitaw ang Tier Compilation, salamat sa kung aling mga programmer ang gugugol ng mas kaunting oras sa paglulunsad ng isang proyekto.
  • Suporta para sa bagong .NET Standards.
  • Suporta para sa isang bagong bersyon ng programming language.
  • Pag-optimize, sa bawat bagong bersyon ang pag-optimize ng mga batayang aklatan Collection/Struct/Stream/String/Regex at marami pang iba. Kung lilipat ka mula sa .NET Framework patungo sa .NET Core, makakakuha ka ng malaking pagpapalakas ng pagganap sa labas ng kahon. Bilang halimbawa, nag-attach ako ng link sa ilan sa mga optimization na idinagdag sa .NET Core 3.0: https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core-3-0/

Pagganap sa .NET Core

Konklusyon

Kapag nagsusulat ng code, ito ay nagkakahalaga ng pagbibigay pansin sa iba't ibang aspeto ng iyong proyekto at paggamit ng mga tampok ng iyong programming language at platform upang makamit ang pinakamahusay na resulta. Natutuwa ako kung ibabahagi mo ang iyong kaalaman na may kaugnayan sa pag-optimize sa .NET.

Link sa github

Pinagmulan: www.habr.com

Magdagdag ng komento