Gotara neserkeftî di derbarê bilezkirina refleksê de

Ez ê tavilê sernavê gotarê rave bikim. Plana bingehîn ev bû ku meriv şîretek baş, pêbawer bide ka meriv çawa bi karanîna mînakek hêsan lê realîst karanîna refleksê bilezîne, lê di dema pîvandinê de derket holê ku refleks ne ew qas hêdî ye ku ez difikirîm, LINQ ji kabûsên min hêdîtir e. Lê di dawiyê de derket holê ku min jî di pîvanan de xeletî kiriye... Hûrguliyên vê çîroka jiyanê di bin birîn û şîroveyan de ne. Ji ber ku mînakek pir gelemperî ye û di prensîbê de wekî ku bi gelemperî di pargîdaniyek de tê kirin tête bicîh kirin, ew xuya bû ku xwenîşandanek jiyanê pir balkêş e, wekî ku ji min re xuya dike: bandora li ser leza mijara sereke ya gotarê bû. ji ber mantiqa derveyî nayê xuyang kirin: Moq, Autofac, EF Core û "bandên" yên din.

Min di bin bandora vê gotarê de dest bi xebatê kir: Çima Reflection hêdî ye

Wekî ku hûn dikarin bibînin, nivîskar li şûna ku rasterast gazîkirina şêwazên cûrbecûr refleksê bike wekî rêyek girîng ji bo bilezkirina serîlêdanê pêşniyar dike ku delegeyên berhevkirî bikar bînin. Bê guman, belavkirina IL-ê heye, lê ez dixwazim jê dûr bibim, ji ber ku ev awayê herî kedkar e ji bo pêkanîna peywirê, ku bi xeletiyan re tije ye.

Bihesibînin ku min her dem di derbarê leza refleksê de ramanek wekhev girtiye, min bi taybetî niyet nekir ku encamên nivîskar bipirsim.

Ez bi gelemperî di pargîdaniyê de bi karanîna nefsbiçûk a refleksê re rû bi rû dimînim. Tîp tê girtin. Agahiyên li ser milk tê girtin. Rêbaza SetValue tê gotin û her kes şa dibe. Nirx gihîştiye qada armancê, her kes kêfxweş e. Mirovên pir jîr - kalûpîr û pêşengên tîmê - pêvekên xwe ji bo îtîrazê dinivîsin, li ser bingehek weha nerast nexşeyên "gerdûnî" yên yek celebek din. Ya bingehîn bi gelemperî ev e: em hemî qadan digirin, hemî taybetmendiyan digirin, li ser wan dubare dikin: heke navên endamên tîpan li hev bikin, em SetValue pêk tînin. Dem bi dem em ji ber xeletiyan îstisnayan digirin ku me di yek ji cûreyan de hin milk nedît, lê li vir jî rêyek heye ku performansê baştir dike. Biceribînin / bigirin.

Min dît ku mirov parser û nexşevanan ji nû ve îcad dikin bêyî ku bi tevahî agahdarî li ser ka makîneyên ku berî wan dixebitin çawa dixebitin. Min dît ku mirov li pişt stratejiyan, li pişt navbeynkaran, li pişt derzîlêdan pêkanînên xwe yên nefsbiçûk vedişêrin, mîna ku ev dê bacchanalia paşerojê biborîne. Min pozê xwe li ser têgihiştinên weha zivirand. Di rastiyê de, min lewaziya performansa rastîn pîv nekir, û, heke gengaz be, ger ku ez bikaribim wê bi dest bixim, min bi tenê pêkanînek ji "optimal" re guhert. Ji ber vê yekê, pîvandinên yekem ên ku li jêr hatine nîqaş kirin ez bi giranî tevlihev kirim.

Ez difikirim ku gelek ji we, Richter an îdeologên din dixwînin, rastî gotinek bi tevahî rast hatine ku refleksa di kodê de fenomenek e ku bandorek zehf neyînî li ser performansa serîlêdanê dike.

Banga refleksê CLR neçar dike ku di meclîsan re derbas bibe da ku ya ku ew hewce dike bibîne, metadata xwe bikişîne, wan parsek bike, hwd. Digel vê yekê, refleks dema ku rêzan derbas dike dibe sedema veqetandina hejmareke mezin a bîranînê. Em bîranînê bikar tînin, CLR GC-yê vedike û firingî dest pê dike. Divê ew hêdî hêdî be, ji min bawer bikin. Rêjeyên mezin ên bîranînê yên li ser serverên hilberîna nûjen an makîneyên ewr rê li ber derengiya bilindkirina pêvajoyê nagirin. Di rastiyê de, her ku bêtir bîranîn, îhtîmal e ku hûn BIBÎNIN ka GC çawa dixebite. Refleksî, di teorîyê de, ji bo wî çîçekek sor a zêde ye.

Lêbelê, em hemî konteynerên IoC û nexşeyên tarîxê bikar tînin, prensîba xebitandinê ya ku di heman demê de li ser refleksê ye jî, lê bi gelemperî di derheqê performansa wan de pirs tune. Na, ne ji ber ku danasîna pêwendiyan û jêbirina ji modelên çarçoveyek tixûbdar a derveyî ew qas hewce ne ku em neçar in ku di her rewşê de performansê bikin qurban. Her tişt hêsan e - ew bi rastî pir bandor li performansê nake.

Rastî ev e ku çarçoveyên herî gelemperî yên ku li ser bingeha teknolojiya refleksê têne damezrandin her cûre hîleyan bikar tînin da ku bi wê re çêtir bixebitin. Bi gelemperî ev cache ye. Bi gelemperî ev îfade û delege ne ku ji dara vegotinê hatine berhev kirin. Heman otomapper ferhengek pêşbaziyê diparêze ku cûreyên bi fonksiyonên ku dikarin bêyî gazîkirina refleksê yek biguhezînin hevdu digire.

Ev çawa tê bidestxistin? Di bingeh de, ev ji mantiqa ku platform bixwe ji bo afirandina koda JIT-ê bikar tîne ne cûda ye. Dema ku rêbazek ji bo cara yekem tê gazî kirin, ew tê berhev kirin (û, erê, ev pêvajo ne bilez e); li ser bangên paşîn, kontrol ji rêbaza ku jixwe hatî berhev kirin ve tê veguheztin, û dê kêmbûna performansê ya girîng tune be.

Di doza me de, hûn dikarin berhevoka JIT-ê jî bikar bînin û dûv re tevgera berhevkirî bi heman performansê wekî hevpîşeyên wê yên AOT bikar bînin. Îfade dê di vê mijarê de alîkariya me bike.

Prensîba navborî dikare bi kurtî wiha were formulekirin:
Pêdivî ye ku hûn encama dawî ya refleksê wekî nûnerek ku fonksiyona berhevkirî vedihewîne cache bikin. Di heman demê de maqûl e ku hûn hemî tiştên hewce bi agahdariya celebê li qadên celebê we, karker, ku li derveyî tiştan têne hilanîn, veşêrin.

Di vê de mantiq heye. Aqilê hevpar ji me re dibêje ku heke tiştek were berhev kirin û vegirtin, wê hingê divê were kirin.

Li pêş me dinihêre, divê were gotin ku cache di xebata bi refleksê de avantajên xwe hene, hetta hûn rêbaza pêşniyarkirî ya berhevkirina îfadeyan bikar neynin. Bi rastî, li vir ez tenê tezên nivîskarê gotara ku li jor behsa wan dikim dubare dikim.

Niha li ser kodê. Werin em li mînakek dinêrin ku li ser êşa min a vê dawîyê ye ku ez neçar bûm ku di hilberînek cidî ya saziyek krediyê ya giran de rû bi rû bim. Hemî sazî xeyalî ne ku kes texmîn neke.

Hin cewher heye. Bila Têkilî hebe. Tîpên bi laşek standardkirî hene, ku ji wan parser û hîdrotor van têkiliyan diafirînin. Nameyek hat, me ew xwend, ew di nav cotên key-nirxê de pars kir, têkiliyek çêkir, û ew di databasê de tomar kir.

Ew bingehîn e. Em bêjin ku têkiliyek xwediyê taybetmendiyên Navê Tev, Temen û Têlefona Têkilî ye. Ev daneyên di nameyê de têne veguhestin. Karsaz di heman demê de piştgirî dixwaze ku bikaribe zû bişkokên nû ji bo nexşekirina taybetmendiyên sazûmanan li cotan di laşê nameyê de zêde bike. Ger kesek di şablonê de xeletiyek tîpî çêkir an jî berî berdanê pêdivî ye ku bi lezgîn nexşe ji hevalbendek nû dest pê bike, li gorî formata nû were adaptekirin. Wê hingê em dikarin pêwendiyek nexşeyê ya nû wekî datafixek erzan zêde bikin. Yanî mînaka jiyanê.

Em pêk tînin, ceribandinan diafirînin. Works.

Ez ê kodê peyda nekim: gelek çavkanî hene, û ew li ser GitHub bi lînka di dawiya gotarê de peyda dibin. Hûn dikarin wan bar bikin, ji nedîtî ve wan îşkence bikin û wan bipîvin, ji ber ku ew ê di doza we de bandor bike. Ez ê tenê koda du awayên şablonê bidim ku hîdrotorê, ku diviyabû bilez be, ji hîdrotorê, ku diviyabû hêdî be, cihê dike.

Mantiq wiha ye: rêbaza şablonê cotên ku ji hêla mantiqa bingehîn a parserê ve hatî çêkirin distîne. Qata LINQ parserker û mantiqa bingehîn a hîdrotorê ye, ku daxwazek ji çarçoweya databasê re dike û bişkojan bi cotên parserê re berhev dike (ji bo van fonksiyonan kodek bêyî LINQ ji bo berhevdanê heye). Dûv re, cot derbasî rêbaza hîdrokirinê ya sereke dibin û nirxên cotan li taybetmendiyên têkildar ên saziyê têne danîn.

"Fast" (Di pîvanan de Pêşgira Fast):

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

Wekî ku em dibînin, berhevokek statîk bi taybetmendiyên setter tê bikar anîn - lambdayên berhevkirî yên ku gazî sazûmana sazker dikin. Ji hêla koda jêrîn ve hatî afirandin:

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

Bi gelemperî ew eşkere ye. Em li taybetmendiyan diherikin, ji wan re delegeyan diafirînin ku gazî sazkeran dikin, û wan xilas dikin. Wê demê dema pêwîst be em bang dikin.

"Hêdî" (Di pîvanan de Pêşgira Hêdî):

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

Li vir em tavilê taybetmendiyan derbas dikin û rasterast gazî SetValue dikin.

Ji bo zelalbûn û wekî referansê, min rêbazek nefsbiçûk bicîh kir ku nirxên cotên pêwendiya wan rasterast di nav zeviyên sazûmanê de dinivîse. Pêşgir - Manual.

Naha em werin BenchmarkDotNet bigirin û performansê lêkolîn bikin. Û ji nişkê ve ... (spoiler - ev ne encama rast e, hûrgulî li jêr in)

Gotara neserkeftî di derbarê bilezkirina refleksê de

Em li vir çi dibînin? Rêbazên ku bi serfirazî pêşgira Fast hildigirin hema hema di hemî derbazan de ji rêbazên bi pêşgira Slow hêdîtir derdikevin. Ev hem ji bo veqetandin û hem jî ji bo leza xebatê rast e. Ji hêla din ve, pêkanîna xweşik û xweşik a nexşeyê bi karanîna rêbazên LINQ-ê ku ji bo vê yekê hatî armanc kirin, li ku derê gengaz be, berevajî vê yekê, hilberîneriyê pir kêm dike. Ferqa rêzê ye. Trend bi hejmarên cûda yên derbasbûnê nayê guhertin. Cûdahiya tenê di pîvanê de ye. Bi LINQ re ew 4 - 200 carî hêdîtir e, li ser heman pîvanê bêtir zibil heye.

NÛKIRIN

Min ji çavên xwe bawer nekir, lê ya girîngtir, hevkarê me ne ji çavên min û ne jî ji koda min bawer nekir - Dmitriy Tikhonov 0x1000000. Piştî ku çareseriya min ducarî kontrol kir, wî bi ronî xeletiyek dît û destnîşan kir ku min ji ber gelek guhertinên di pêkanînê de, ji destpêkê heya dawîn, winda kir. Piştî rastkirina xeletiya ku di sazkirina Moq de hate dîtin, hemî encam ketin cihê xwe. Li gorî encamên ji nû ve ceribandinê, meyla sereke naguhere - LINQ hîn jî ji refleksê bêtir bandorê li performansê dike. Lêbelê, xweş e ku xebata bi berhevkirina Expressionê re vala nayê kirin, û encam hem di dema veqetandinê û hem jî di dema darvekirinê de xuya ye. Destpêka yekem, dema ku zeviyên statîk têne destpêkirin, bi xwezayî ji bo rêbaza "zû" hêdîtir e, lê paşê rewş diguhere.

Li vir encama ceribandinê ye:

Gotara neserkeftî di derbarê bilezkirina refleksê de

Encam: dema ku di pargîdaniyek de refleksê bikar bînin, ne hewce ye ku meriv serî li hîleyan bide - LINQ dê bêtir hilberînê bixwe. Lêbelê, di rêbazên bargiraniya bilind ên ku xweşbîniyê hewce dikin de, hûn dikarin refleksê di forma destpêker û berhevkeran de hilînin, ku wê hingê mantiqa "zû" peyda bikin. Bi vî rengî hûn dikarin hem nermbûna refleksê û hem jî leza serîlêdanê biparêzin.

Koda pîvanê li vir heye. Her kes dikare gotinên min ducar kontrol bike:
HabraReflectionTests

PS: koda di ceribandinan de IoC bikar tîne, û di pîvanan de ew avahiyek eşkere bikar tîne. Rastî ev e ku di pêkanîna paşîn de min hemî faktorên ku dikarin bandorê li performansê bikin û encamê dengdar bikin qut kirin.

PPS: Spas ji bo bikarhêner Dmitriy Tikhonov @0x1000000 ji bo vedîtina xeletiya min di sazkirina Moq de, ku bandor li pîvandinên yekem kir. Ger yek ji xwendevanan karma têra xwe hebe, ji kerema xwe hez bikin. Mêrik sekinî, mêrik xwend, mêrik ducarî kontrol kir û xeletî îşaret kir. Ez wisa difikirim ku ev hêjayî rêzgirtin û sempatiyê ye.

PPPS: spas ji xwendevanê hûrgilî re ku gihîştiye binê şêwaz û sêwiranê. Ez ji bo yekrengî û rehetiyê me. Dîplomasiya danasînê gelek tiştan dihêle, lê min rexne li ber çav girt. Ez projeyekê dipirsim.

Source: www.habr.com

Add a comment