Misheppnuð grein um hraða endurskoðun

Ég mun strax útskýra titil greinarinnar. Upphaflega áætlunin var að gefa góð og áreiðanleg ráð um hvernig hægt væri að flýta fyrir notkun endurkasts með einföldu en raunhæfu dæmi, en við verðsamanburð kom í ljós að speglun er ekki eins hæg og ég hélt, LINQ er hægari en í martröðum mínum. En á endanum kom í ljós að ég gerði líka mistök í mælingum... Upplýsingar um þessa lífssögu eru undir klippingu og í athugasemdum. Þar sem dæmið er nokkuð algengt og útfært í grundvallaratriðum eins og venjulega er gert í fyrirtæki, reyndist það vera nokkuð áhugaverð, eins og mér sýnist, sýning á lífinu: áhrifin á hraða aðalefnis greinarinnar voru ekki áberandi vegna ytri rökfræði: Moq, Autofac, EF Core og fleiri "ólar".

Ég byrjaði að vinna undir áhrifum þessarar greinar: Hvers vegna er Reflection hægt

Eins og þú sérð leggur höfundurinn til að þú notir samansetta fulltrúa í stað þess að kalla beint spegilmyndaraðferðir sem frábær leið til að flýta mjög fyrir forritinu. Það er auðvitað IL losun, en ég vil forðast það, þar sem þetta er erfiðasta leiðin til að framkvæma verkefnið, sem er fullt af villum.

Í ljósi þess að ég hef alltaf haft svipaða skoðun á hraða íhugunar, ætlaði ég ekki sérstaklega að efast um niðurstöður höfundar.

Ég lendi oft í barnalegri notkun á íhugun í fyrirtækinu. Tegundin er tekin. Tekið er við upplýsingum um eignina. SetValue aðferðin er kölluð og allir fagna. Verðmætin eru komin í markið, allir ánægðir. Mjög klárt fólk - eldri borgarar og liðsforingjar - skrifa viðbætur sínar til mótmæla, byggir á svo barnalegri útfærslu "alhliða" kortagerðarmenn af einni gerð til annarrar. Kjarninn er venjulega þessi: við tökum alla reiti, tökum alla eiginleika, endurtekum yfir þá: ef nöfn tegundameðlimanna passa, keyrum við SetValue. Af og til grípum við til undantekningar vegna mistaka þar sem við fundum ekki einhverja eign í einni af tegundunum, en jafnvel hér er leið út sem bætir afköst. Prófaðu / grípa.

Ég hef séð fólk finna upp þáttara og kortara án þess að vera fullvopnaðir upplýsingum um hvernig vélarnar sem komu á undan þeim virka. Ég hef séð fólk fela barnalegar útfærslur sínar á bak við aðferðir, á bak við viðmót, á bak við inndælingar, eins og þetta myndi afsaka síðari bakkanalíu. Ég rak upp nefið á slíkum skilningi. Reyndar mældi ég ekki raunverulegan frammistöðuleka og, ef hægt var, breytti ég einfaldlega útfærslunni í „ákjósanlegri“ ef ég gæti fengið hana í hendurnar. Þess vegna rugluðu fyrstu mælingarnar sem fjallað er um hér að neðan mig alvarlega.

Ég held að mörg ykkar, lesandi Richter eða aðrir hugmyndafræðingar, hafi rekist á fullkomlega sanngjarna staðhæfingu um að speglun í kóða sé fyrirbæri sem hafi afar neikvæð áhrif á frammistöðu forritsins.

Að hringja í spegilmynd neyðir CLR til að fara í gegnum samsetningar til að finna það sem þeir þurfa, draga upp lýsigögn þeirra, flokka þau o.s.frv. Að auki leiðir spegilmynd meðan farið er yfir röð til úthlutunar á miklu minni. Við erum að nota upp minni, CLR afhjúpar GC og frísur byrja. Það ætti að vera áberandi hægt, trúðu mér. Mikið magn af minni á nútíma framleiðsluþjónum eða skýjavélum kemur ekki í veg fyrir miklar vinnslutafir. Í raun, því meira minni, því líklegra er að þú takir eftir því hvernig GC virkar. Hugleiðing er í orði, auka rauð tuska fyrir hann.

Hins vegar notum við öll IoC gáma og dagsetningarkortara, en rekstrarreglan er einnig byggð á ígrundun, en það eru yfirleitt engar spurningar um frammistöðu þeirra. Nei, ekki vegna þess að innleiðing á ósjálfstæði og útdrætti frá ytri takmörkuðu samhengislíkönum er svo nauðsynleg að við verðum að fórna frammistöðu í öllum tilvikum. Allt er einfaldara - það hefur í raun ekki mikil áhrif á frammistöðu.

Staðreyndin er sú að algengustu umgjörðirnar sem byggjast á endurskinstækni nota alls kyns brellur til að vinna með það sem best. Venjulega er þetta skyndiminni. Venjulega eru þetta tjáningar og fulltrúar settir saman úr tjáningartrénu. Sami automapper heldur úti samkeppnisorðabók sem passar við tegundir með aðgerðum sem geta umbreytt hverri í aðra án þess að kalla á spegilmynd.

Hvernig er þetta náð? Í meginatriðum er þetta ekkert frábrugðið rökfræðinni sem pallurinn sjálfur notar til að búa til JIT kóða. Þegar aðferð er kölluð í fyrsta skipti er hún tekin saman (og já, þetta ferli er ekki hratt); í síðari símtölum er stjórnin færð yfir á þá aðferð sem þegar hefur verið sett saman og það verður engin marktæk afköst.

Í okkar tilviki geturðu líka notað JIT samantekt og síðan notað samansettu hegðunina með sömu frammistöðu og AOT hliðstæða þess. Tjáningar munu koma okkur til hjálpar í þessu máli.

Umrædda meginreglu má í stuttu máli orða þannig:
Þú ættir að vista lokaniðurstöðu íhugunar sem fulltrúi sem inniheldur samansetta aðgerðina. Það er líka skynsamlegt að vista alla nauðsynlega hluti með tegundarupplýsingum á sviðum tegundarinnar þinnar, starfsmannsins, sem eru geymdir fyrir utan hlutina.

Það er rökfræði í þessu. Skynsemi segir okkur að ef hægt er að safna einhverju saman og vista í skyndiminni þá ætti það að vera gert.

Þegar horft er fram á veginn ætti að segja að skyndiminni við að vinna með speglun hefur sína kosti, jafnvel þótt þú notir ekki fyrirhugaða aðferð til að setja saman tjáningar. Reyndar er ég hér einfaldlega að endurtaka ritgerðir höfundar greinarinnar sem ég vísa til hér að ofan.

Nú um kóðann. Við skulum skoða dæmi sem er byggt á nýlegum sársauka mínum sem ég þurfti að horfast í augu við í alvarlegri framleiðslu alvarlegrar lánastofnunar. Allar einingar eru uppspuni svo að enginn myndi giska á.

Það er einhver kjarni. Látum það vera samband. Það eru stafir með stöðluðum meginmáli, sem flokkarinn og vökvarinn búa til þessa sömu tengiliði. Bréf barst, við lásum það, flokkuðum það í lykilgildapör, bjuggum til tengilið og vistuðum það í gagnagrunninum.

Það er grunnskólastig. Segjum að tengiliður hafi eiginleikana fullt nafn, aldur og símanúmer. Þessi gögn eru send í bréfinu. Fyrirtækið vill einnig stuðning til að geta fljótt bætt við nýjum lyklum til að kortleggja eiginleika eininga í pör í meginmáli bréfsins. Ef einhver gerði innsláttarvillu í sniðmátinu eða ef fyrir útgáfu er nauðsynlegt að hefja kortlagningu strax frá nýjum samstarfsaðila, aðlaga sig að nýju sniði. Þá getum við bætt við nýrri kortlagningarfylgni sem ódýrri gagnaleiðréttingu. Semsagt lífsdæmi.

Við innleiðum, búum til próf. Virkar.

Ég mun ekki gefa upp kóðann: það eru margar heimildir og þær eru fáanlegar á GitHub með hlekknum í lok greinarinnar. Þú getur hlaðið þau, pyntað þau óþekkjanlega og mælt þau, eins og það hefði áhrif í þínu tilviki. Ég mun aðeins gefa upp kóðann af tveimur sniðmátsaðferðum sem aðgreina vökvakerfið, sem átti að vera hratt, frá vökvakerfinu, sem átti að vera hægt.

Rökfræðin er sem hér segir: sniðmátsaðferðin tekur á móti pörum sem myndast af grunnþáttarrökfræðinni. LINQ lagið er þáttarinn og grunnrökfræði hydratorsins, sem gerir beiðni um gagnagrunnssamhengið og ber saman lykla við pör frá þáttaranum (fyrir þessar aðgerðir er kóða án LINQ til samanburðar). Næst eru pörin send yfir í aðalvökvunaraðferðina og gildi pöranna eru stillt á samsvarandi eiginleika einingarinnar.

„Fast“ (Forskeyti Fast í viðmiðum):

 protected override Contact GetContact(PropertyToValueCorrelation[] correlations)
        {
            var contact = new Contact();
            foreach (var setterMapItem in _proprtySettersMap)
            {
                var correlation = correlations.FirstOrDefault(x => x.PropertyName == setterMapItem.Key);
                setterMapItem.Value(contact, correlation?.Value);
            }
            return contact;
        }

Eins og við sjáum er notað kyrrstætt safn með settareiginleikum - samsettar lambda sem kalla á setter eininguna. Búið til með eftirfarandi kóða:

        static FastContactHydrator()
        {
            var type = typeof(Contact);
            foreach (var property in type.GetProperties())
            {
                _proprtySettersMap[property.Name] = GetSetterAction(property);
            }
        }

        private static Action<Contact, string> GetSetterAction(PropertyInfo property)
        {
            var setterInfo = property.GetSetMethod();
            var paramValueOriginal = Expression.Parameter(property.PropertyType, "value");
            var paramEntity = Expression.Parameter(typeof(Contact), "entity");
            var setterExp = Expression.Call(paramEntity, setterInfo, paramValueOriginal).Reduce();
            
            var lambda = (Expression<Action<Contact, string>>)Expression.Lambda(setterExp, paramEntity, paramValueOriginal);

            return lambda.Compile();
        }

Almennt séð er það ljóst. Við förum yfir eignirnar, búum til fulltrúa fyrir þá sem hringja í stillingar og vistum þá. Svo hringjum við þegar þörf krefur.

„Slow“ (Forskeyti Slow í viðmiðum):

        protected override Contact GetContact(PropertyToValueCorrelation[] correlations)
        {
            var contact = new Contact();
            foreach (var property in _properties)
            {
                var correlation = correlations.FirstOrDefault(x => x.PropertyName == property.Name);
                if (correlation?.Value == null)
                    continue;

                property.SetValue(contact, correlation.Value);
            }
            return contact;
        }

Hér förum við strax framhjá eignunum og hringjum beint í SetValue.

Til glöggvunar og til viðmiðunar innleiddi ég barnalega aðferð sem skrifar gildi fylgnipöra þeirra beint inn í einingareitin. Forskeyti - Handbók.

Nú skulum við taka BenchmarkDotNet og skoða frammistöðuna. Og allt í einu... (spoiler - þetta er ekki rétt niðurstaða, upplýsingar eru hér að neðan)

Misheppnuð grein um hraða endurskoðun

Hvað sjáum við hér? Aðferðir sem bera hrósandi forskeytið Hratt reynast hægari í næstum öllum sendingum en aðferðir með Slow forskeytið. Þetta á bæði við um úthlutun og vinnuhraða. Hins vegar dregur falleg og glæsileg útfærsla á kortlagningu með LINQ aðferðum sem ætlaðar eru til þess þar sem hægt er, þvert á móti mjög úr framleiðni. Munurinn er í röð. Þróunin breytist ekki með mismunandi fjölda sendinga. Eini munurinn er í mælikvarða. Með LINQ er það 4 - 200 sinnum hægara, það er meira sorp á um það bil sama mælikvarða.

UPPFÆRT

Ég trúði ekki mínum eigin augum, en það sem meira er, samstarfsmaður okkar trúði hvorki mínum augum né kóðanum mínum - Dmitry Tikhonov 0x1000000. Eftir að hafa athugað lausnina mína uppgötvaði hann frábærlega og benti á villu sem ég missti af vegna fjölda breytinga á útfærslunni, upphaflega til loka. Eftir að hafa lagfært villuna sem fannst í Moq uppsetningunni féllu allar niðurstöður á sinn stað. Samkvæmt niðurstöðum endurprófunar breytist aðalstefnan ekki - LINQ hefur enn meiri áhrif á frammistöðu en endurspeglun. Hins vegar er gaman að vinnan með Expression samantekt er ekki unnin til einskis og niðurstaðan sést bæði í úthlutun og framkvæmdartíma. Fyrsta ræsingin, þegar kyrrstöðureitir eru frumstilltir, er náttúrulega hægari fyrir „hröðu“ aðferðina, en þá breytist staðan.

Hér er niðurstaða endurprófsins:

Misheppnuð grein um hraða endurskoðun

Ályktun: þegar spegilmynd er notuð í fyrirtæki er engin sérstök þörf á að grípa til brellna - LINQ mun éta framleiðni meira. Hins vegar, í háhleðsluaðferðum sem krefjast hagræðingar, geturðu vistað endurspeglun í formi frumstilla og fulltrúa þýðenda, sem munu síðan veita „hraða“ rökfræði. Þannig geturðu viðhaldið bæði sveigjanleika endurspeglunar og hraða forritsins.

Viðmiðunarkóði er fáanlegur hér. Hver sem er getur athugað orð mín:
HabraReflection Tests

PS: kóðinn í prófunum notar IoC og í viðmiðunum notar hann skýra byggingu. Staðreyndin er sú að í endanlegri útfærslu klippti ég alla þætti sem gætu haft áhrif á frammistöðu og gert útkomuna hávaðasama.

PPS: Þökk sé notandanum Dmitry Tikhonov @0x1000000 fyrir að uppgötva villuna mína við að setja upp Moq, sem hafði áhrif á fyrstu mælingar. Ef einhver af lesendum hefur nægilegt karma, vinsamlegast líka við það. Maðurinn stoppaði, maðurinn las, maðurinn tvítékkaði og benti á mistökin. Mér finnst þetta vera virðingar og samúðar virði.

PPPS: þökk sé vandvirkum lesanda sem komst til botns í stíl og hönnun. Ég er fyrir einsleitni og þægindi. Diplómatían í kynningunni skilur mikið eftir, en ég tók gagnrýnina til greina. Ég bið um skotið.

Heimild: www.habr.com

Bæta við athugasemd