Hausnarketa bizkortzeari buruzko artikulu arrakastatsua

Berehala azalduko dut artikuluaren izenburua. Jatorrizko plana hausnarketaren erabilera azkartzeko aholku onak eta fidagarriak ematea zen adibide sinple baina errealista erabiliz, baina benchmarking zehar hausnarketa ez dela uste nuen bezain motela, LINQ nire amesgaiztoetan baino motelagoa da. Baina azkenean neurketetan ere akats bat egin dudala atera da... Bizitza istorio honen xehetasunak mozketan eta iruzkinetan daude. Adibidea nahiko ohikoa denez eta printzipioz enpresa batean egin ohi den bezala inplementatua denez, nahiko interesgarria iruditu zitzaidan, nire ustez, bizitzaren erakustaldia: artikuluaren gai nagusiaren abiaduraren eragina izan zen. ez da nabaritzen kanpoko logikaren ondorioz: Moq, Autofac, EF Core eta beste "bandings".

Artikulu honen inpresioarekin hasi nintzen lanean: Zergatik da motela Hausnarketa

Ikus dezakezun bezala, egileak konpilatutako delegatuak erabiltzea proposatzen du islaketa motako metodoak zuzenean deitu beharrean, aplikazioa asko bizkortzeko modu bikaina baita. Badago, noski, IL igorpena, baina saihestu nahiko nuke, hau baita lana egiteko modurik gehien, akatsez beteta.

Gogoetaren abiadurari buruz beti antzeko iritzia izan dudala kontuan hartuta, ez nuen bereziki egilearen ondorioak zalantzan jartzeko asmorik.

Askotan egiten dut topo hausnarketaren erabilera inozoa enpresan. Mota hartzen da. Jabetzari buruzko informazioa hartzen da. SetValue metodoari deitzen zaio eta denak pozten dira. Balioa helburu eremura iritsi da, denak pozik daude. Pertsona oso adimentsuek - adinekoek eta talde-buruek - beren luzapenak idazten dituzte objektuari, halako inplementazio inozo batean oinarritutako "unibertsalak" mota bateko mapatzaileak. Funtsa hau izan ohi da: eremu guztiak hartzen ditugu, propietate guztiak hartzen ditugu, horien gainean errepikatzen dugu: motako kideen izenak bat datoz, SetValue exekutatzen dugu. Noizean behin salbuespenak atzematen ditugu akatsen ondorioz, motaren batean jabetzaren bat aurkitu ez genuenean, baina hemen ere errendimendua hobetzen duen irteera dago. Saiatu/harrapatu.

Jendeak ikusi ditut analizatzaileak eta mapatzaileak berrasmatu gabe, aurretik zetozen makinek nola funtzionatzen zutenari buruzko informazio guztiz armaturik egon gabe. Ikusi dut jendea estrategien atzean, interfazeen atzean, injekzioen atzean bere inplementazio inozoak ezkutatzen, honek ondorengo bakanalak aitzakia izango balu bezala. Sudurra piztu nuen halako kontuetan. Izan ere, ez nuen benetako errendimendu-isuria neurtu, eta, ahal izanez gero, inplementazioa "optimoago" batera aldatu besterik ez nuen egin, eskua eskuratzen banu. Hori dela eta, jarraian aztertutako lehen neurketek larri nahastu ninduten.

Uste dut zuetako askok, Richter edo beste ideologo batzuk irakurtzen, guztiz bidezko adierazpenarekin topo egin duzula kodean islatzea aplikazioaren errendimenduan oso eragin negatiboa duen fenomenoa dela.

Hausnarketa deitzeak CLR batzarretan zehar behartzen du behar duena aurkitzeko, metadatuak ateratzeko, analizatzeko, etab. Horrez gain, sekuentziak zeharkatzean hausnartzeak memoria kopuru handia esleitzea dakar. Memoria erabiltzen ari gara, CLR-k GC deskubritzen du eta frisoak hasten dira. Nabarmen motela izan beharko luke, sinetsi. Ekoizpen zerbitzari modernoen edo hodeiko makinen memoria kopuru handiek ez dute prozesatzeko atzerapen handiak eragozten. Izan ere, zenbat eta memoria gehiago, orduan eta probabilitate handiagoa izango duzu GC-k nola funtzionatzen duen OHARRA izateko. Hausnarketa, teorian, trapu gorri gehigarria da berarentzat.

Hala ere, denok erabiltzen ditugu IoC edukiontziak eta data-mapatzaileak, horien funtzionamendu-printzipioa ere hausnarketan oinarritzen da, baina normalean ez dago haien errendimenduari buruzko galderarik. Ez, ez menpekotasunak eta kanpoko testuinguru mugatuko ereduetatik abstrakzioa sartzea hain beharrezkoak direnez, edozein kasutan errendimendua sakrifikatu behar dugulako. Dena sinpleagoa da - benetan ez du errendimenduan asko eragiten.

Kontua da hausnarketa teknologian oinarritzen diren marko ohikoenek era guztietako trikimailuak erabiltzen dituztela modu optimoagoan lan egiteko. Normalean hau cache bat da. Normalean, adierazpenen zuhaitzetik konpilatutako Adierazpenak eta ordezkariak dira. Automapper berak gogoeta deitu gabe batak beste bihur daitezkeen funtzioekin bat egiten duen hiztegi lehiakorra mantentzen du.

Nola lortzen da hori? Funtsean, hori ez da ezberdina plataformak berak JIT kodea sortzeko erabiltzen duen logikarekin. Metodo bat lehen aldiz deitzen denean, konpilatu egiten da (eta, bai, prozesu hau ez da azkarra); hurrengo deietan, kontrola dagoeneko konpilatutako metodora transferitzen da, eta ez da errendimenduaren murrizketa nabarmenik izango.

Gure kasuan, JIT konpilazioa ere erabil dezakezu eta, ondoren, konpilatutako portaera erabil dezakezu bere AOT-en parekoen errendimendu berdinarekin. Adierazpenak gure laguntza etorriko zaizkigu kasu honetan.

Aipatutako printzipioa laburki honela formula daiteke:
Hausnarketaren azken emaitza konpilatutako funtzioa duen delegatu gisa gorde behar duzu. Era berean, zentzuzkoa da objektuetatik kanpo gordetzen diren zure motako eremuetan, langilea, motako informazioa duten beharrezko objektu guztiak cachean jartzea.

Honetan logika dago. Zentzu onak esaten digu zerbait konpilatu eta cachean gorde daitekeela, egin beharko litzatekeela.

Aurrera begira, esan beharra dago hausnarketa lantzean cacheak bere abantailak dituela, nahiz eta espresioak biltzeko proposatutako metodoa ez erabili. Egia esan, hemen goian aipatzen dudan artikuluaren egilearen tesiak errepikatzen ari naiz besterik gabe.

Orain kodeari buruz. Ikus dezagun kreditu-erakunde serio baten ekoizpen serio batean egin behar izan dudan azken minean oinarritzen den adibide bat. Entitate guztiak fikziozkoak dira, inork asmatu ez dezan.

Bada esentziaren bat. Izan dadila Kontaktua. Gorputz estandarizatua duten letrak daude, eta bertatik analizatzaileak eta hidratatzaileak kontaktu hauek sortzen dituzte. Gutun bat iritsi zen, irakurri, gako-balio pareetan aztertu, kontaktu bat sortu eta datu-basean gorde genuen.

Oinarrizkoa da. Demagun kontaktu batek izen-abizenak, adina eta harremanetarako telefonoa dituela. Datu horiek gutunean transmititzen dira. Enpresak laguntza ere nahi du gutunaren gorputzean entitateen propietateak bikoteka mapatzeko gako berriak azkar gehitu ahal izateko. Norbaitek txantiloian akatsen bat egin badu edo kaleratu baino lehen beharrezkoa bada mapping abiaraztea bazkide berri batetik, formatu berrira egokituz. Ondoren, mapa-korrelazio berri bat gehi dezakegu datu-konponketa merkea gisa. Hau da, bizitzaren adibide bat.

Inplementatzen dugu, probak sortzen ditugu. Obrak.

Ez dut kodea emango: iturri asko daude, eta GitHub-en eskuragarri daude artikuluaren amaierako estekaren bidez. Kargatu, torturatu eta neurtu ditzakezu, zure kasuan eragingo lukeen bezala. Azkarra izan behar zen hidratatzailea eta motela izan behar zuen hidratatzailea bereizten duten bi txantiloi metodoen kodea bakarrik emango dut.

Logika hau da: txantiloiaren metodoak oinarrizko analizatzaile logikak sortutako bikoteak jasotzen ditu. LINQ geruza analizatzailea da eta hidratatzailearen oinarrizko logika, datu-basearen testuinguruari eskaera bat egiten diona eta analizatzaileko bikoteekin gakoak konparatzen ditu (funtzio hauetarako LINQ gabeko kodea dago konparaziorako). Ondoren, bikoteak hidratazio metodo nagusira pasatzen dira eta bikoteen balioak entitateari dagozkion propietateetara ezartzen dira.

"Azkarra" (Aurrizkia Azkar erreferentzietan):

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

Ikus dezakegunez, setter propietateak dituen bilduma estatiko bat erabiltzen da - setter entitatea deitzen duten lambda konpilatuak. Kode honek sortua:

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

Orokorrean argi dago. Propietateak zeharkatzen ditugu, ezartzaileak deitzen dituzten delegatuak sortzen ditugu eta gordetzen ditugu. Ondoren, beharrezkoa denean deitzen dugu.

"Slow" (Motel aurrizkia erreferentzia-puntuetan):

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

Hemen propietateak berehala baztertzen ditugu eta zuzenean SetValue deitzen dugu.

Argitasunerako eta erreferentzia gisa, haien korrelazio bikoteen balioak zuzenean entitate-eremuetan idazten dituen metodo inozoa ezarri nuen. Aurrizkia – Eskuliburua.

Har dezagun orain BenchmarkDotNet eta azter dezagun errendimendua. Eta bat-batean... (spoiler - hau ez da emaitza zuzena, xehetasunak behean daude)

Hausnarketa bizkortzeari buruzko artikulu arrakastatsua

Zer ikusten dugu hemen? Azkar aurrizkia garaile duten metodoak motelagoak izaten dira ia pase guztietan Slow aurrizkia duten metodoak baino. Hori egia da esleipenerako eta lanaren abiadurarako. Bestalde, horretarako diseinatutako LINQ metodoak erabiliz kartografiaren inplementazio eder eta dotore batek, ahal den guztietan, aitzitik, produktibitatea asko murrizten du. Aldea ordenakoa da. Joera ez da aldatzen pase kopuru ezberdinekin. Desberdintasun bakarra eskalan dago. LINQ-rekin 4-200 aldiz motelagoa da, gutxi gorabehera eskala berean zabor gehiago dago.

EGUNERATUA

Ez nituen nire begiak sinesten, baina are garrantzitsuagoa dena, gure lankideak ez zituen ez nire begiak ez nire kodea sinesten - Dmitry Tikhonov 0x1000000. Nire irtenbidea bikoiztu ondoren, bikain deskubritu eta adierazi zuen inplementazioan izandako hainbat aldaketaren ondorioz galdu nuen errore bat, hasieratik amaierara. Moq-en konfigurazioan aurkitutako akatsa konpondu ondoren, emaitza guztiak tokian jarri ziren. Berriro probaren emaitzen arabera, joera nagusia ez da aldatzen - LINQ-ek errendimenduari eragiten dio errendimenduari gogoeta baino. Hala ere, polita da Expression konpilazioarekin lana alferrik egitea ez izatea, eta emaitza ikusgai egotea bai esleipenean bai exekuzio denboran. Lehenengo abiarazpena, eremu estatikoak hasieratzen direnean, motelagoa da metodo "bizkorra"rako, baina gero egoera aldatzen da.

Hona hemen berriro probaren emaitza:

Hausnarketa bizkortzeari buruzko artikulu arrakastatsua

Ondorioa: enpresa batean hausnarketa erabiltzean, ez dago trikimailuetara jo beharrik - LINQ-ek produktibitatea gehiago jango du. Hala ere, optimizazioa behar duten karga handiko metodoetan, hasierako eta konpiladore delegatu moduan gorde dezakezu hausnarketa, gero logika "bizkorra" emango dutenak. Horrela islapenaren malgutasuna eta aplikazioaren abiadura mantendu ahal izango dituzu.

Erreferentziazko kodea hemen dago eskuragarri. Edonork egiaztatu ditzake nire hitzak:
HabraReflectionTests

PS: probetan kodeak IoC erabiltzen du, eta benchmarketan eraikuntza esplizitu bat erabiltzen du. Kontua da azken ezarpenean errendimenduan eragina izan dezaketen faktore guztiak moztu ditudala eta emaitza zaratatsua izan dadin.

PPS: Eskerrik asko erabiltzaileari Dmitry Tikhonov @0x1000000 Moq konfiguratzean nire akatsa aurkitzeagatik, lehen neurketetan eragina izan zuena. Irakurleren batek karma nahikoa badu, mesedez gustatu. Gizona gelditu zen, gizonak irakurri zuen, gizonak bi aldiz egiaztatu zuen eta akatsa adierazi zuen. Uste dut honek errespetua eta sinpatia merezi duela.

PPPS: estiloaren eta diseinuaren oinarrian sartu zen irakurle zorrotzari esker. Uniformetasunaren eta erosotasunaren alde nago. Aurkezpenaren diplomaziak zer den asko uzten du, baina kritika kontuan hartu nuen. Proyectila eskatzen dut.

Iturria: www.habr.com

Gehitu iruzkin berria