Artikel gagal ngeunaan ngagancangkeun réfléksi

Kuring gé langsung ngajelaskeun judul artikel. Rencana aslina éta méré alus, nasehat dipercaya dina cara nyepetkeun pamakéan réfléksi maké conto basajan tapi realistis, tapi salila benchmarking tétéla yén réfléksi teu sakumaha slow sakumaha Teu sangka, LINQ leuwih laun ti dina nightmares kuring. Tapi tungtungna tétéla kuring ogé nyieun kasalahan dina ukuran ... Rincian carita hirup ieu dina cut na di komentar. Kusabab conto anu cukup umum sareng dilaksanakeun sacara prinsip sapertos anu biasana dilakukeun dina perusahaan, tétéla éta rada pikaresepeun, sakumaha sigana kuring, demonstrasi kahirupan: dampak dina laju subjek utama tulisan éta. teu noticeable alatan logika éksternal: Moq, Autofac, EF Core jeung sajabana "bandings".

Kuring mimiti damel dina kesan tulisan ieu: Naha Refleksi slow

Sakumaha anjeun tiasa tingali, panulis nyarankeun ngagunakeun delegasi disusun tinimbang langsung nelepon métode tipe cerminan salaku cara hébat kana greatly nyepetkeun aplikasi. Aya, tangtosna, émisi IL, tapi kuring hoyong nyingkahan éta, sabab ieu mangrupikeun cara anu paling padat karya pikeun ngalaksanakeun tugas, anu pinuh ku kasalahan.

Nganggap yén kuring sok gaduh pendapat anu sami ngeunaan laju réfléksi, kuring henteu hoyong naroskeun kasimpulan panulis.

Kuring mindeng sapatemon pamakéan naif tina cerminan di perusahaan. Jenisna dicandak. Émbaran ngeunaan harta dicokot. Metoda SetValue disebut jeung dulur rejoices. Ajén geus anjog ka lapang udagan, saréréa bagja. Jalma anu pinter pisan - manula sareng pimpinan tim - nyerat ekstensina pikeun obyék, dumasar kana palaksanaan naif sapertos "universal" mappers tina hiji jinis ka anu sanés. Intina biasana kieu: urang nyandak sagala widang, nyandak sakabeh sipat, iterate leuwih aranjeunna: lamun ngaran anggota tipe cocog, urang ngaéksekusi SetValue. Ti jaman ka jaman urang nyekel iwal alatan kasalahan dimana urang teu manggihan sababaraha harta di salah sahiji jenis, tapi malah didieu aya jalan kaluar nu ngaronjatkeun kinerja. Coba / nyekel.

Kuring geus katempo jalma reinvent parsers na mappers tanpa keur pinuh pakarang kalayan informasi ngeunaan kumaha mesin nu datang saméméh maranéhna jalan. Kuring geus katempo jalma nyumputkeun implementations naif maranéhanana balik strategi, balik interfaces, balik injections, saolah-olah ieu bakal maafkan nu bacchanalia saterusna. Kuring ngahurungkeun irung kuring nepi ka realisasi kitu. Nyatana, kuring henteu ngukur kabocoran kinerja anu nyata, sareng, upami mungkin, kuring ngan ukur ngarobih palaksanaan ka anu langkung "optimal" upami kuring tiasa nampi panangan. Ku alatan éta, pangukuran munggaran dibahas di handap serius bingung kuring.

Jigana loba anjeun, maca Richter atawa ideologists séjén, geus datang di sakuliah hiji pernyataan sagemblengna adil yén réfléksi kode mangrupakeun fenomena anu boga dampak pisan négatip on kinerja aplikasi.

Refleksi nelepon maksakeun CLR ngaliwat majelis pikeun milarian anu diperyogikeun, narik metadatana, nga-parse aranjeunna, jsb. Sajaba ti éta, réfléksi bari traversing runtuyan ngabalukarkeun alokasi jumlah badag memori. Kami nganggo mémori, CLR ngabongkar GC sareng friezes dimimitian. Ieu kudu noticeably slow, percanten ka kuring. Jumlah mémori anu ageung dina server produksi modern atanapi mesin awan henteu nyegah telat pamrosésan anu luhur. Nyatana, langkung seueur mémori, langkung dipikaresep anjeun PERHATOSAN kumaha GC jalanna. Refleksi, dina tiori, rag beureum tambahan pikeun anjeunna.

Nanging, urang sadayana nganggo wadah IoC sareng peta tanggal, prinsip operasi anu ogé dumasar kana réfléksi, tapi biasana henteu aya patarosan ngeunaan pagelaranana. Henteu, sanés kusabab ngenalkeun katergantungan sareng abstraksi tina modél kontéks kawates éksternal anu peryogi pisan yén urang kedah ngorbankeun kinerja dina sagala hal. Sadayana langkung saderhana - éta leres-leres henteu mangaruhan kinerja.

Kanyataanna nyaéta kerangka anu paling umum anu didasarkeun kana téknologi réfléksi ngagunakeun sagala rupa trik pikeun dianggo kalayan langkung optimal. Biasana ieu cache a. Biasana ieu Babasan sareng utusan disusun tina tangkal éksprési. Automapper anu sami ngajaga kamus kalapa anu cocog sareng jinis-jinis sareng fungsi anu tiasa ngarobih hiji kana anu sanés tanpa nelepon réfléksi.

Kumaha ieu kahontal? Intina, ieu henteu béda sareng logika anu dianggo ku platform sorangan pikeun ngahasilkeun kode JIT. Nalika metoda disebut pikeun kahiji kalina, éta disusun (jeung, enya, prosés ieu teu gancang); dina sauran saterusna, kontrol ditransferkeun ka metoda geus disusun, sarta moal aya drawdowns kinerja signifikan.

Dina kasus urang, anjeun ogé tiasa nganggo kompilasi JIT teras nganggo paripolah anu disusun kalayan kinerja anu sami sareng mitra AOT na. Ungkapan bakal ngabantosan urang dina hal ieu.

Prinsip anu dimaksud tiasa dirumuskeun sacara ringkes kieu:
Anjeun kedah cache hasil ahir refleksi salaku utusan anu ngandung fungsi anu disusun. Éta ogé masuk akal pikeun cache sadaya objék anu diperyogikeun kalayan inpormasi jinis dina widang jinis anjeun, pagawé, anu disimpen di luar objék.

Aya logika dina ieu. Akal sehat nyarioskeun ka urang yén upami aya anu tiasa disusun sareng di-cache, maka éta kedah dilakukeun.

Ningali payun, éta kedah disebatkeun yén cache dina damel sareng réfléksi ngagaduhan kaunggulan, sanaos anjeun henteu nganggo metodeu anu diusulkeun pikeun nyusun éksprési. Sabenerna, di dieu kuring ngan ukur ngulang tesis panulis tulisan anu kuring rujuk di luhur.

Ayeuna ngeunaan kode. Hayu urang nempo conto anu dumasar kana nyeri panganyarna kuring nu kuring kungsi nyanghareupan dina produksi serius lembaga kiridit serius. Sadaya éntitas téh fiktif supados teu aya anu nebak.

Aya sababaraha hakekat. Hayu aya Kontak. Aya hurup sareng awak standar, ti mana parser sareng hydrator nyiptakeun kontak anu sami. Hiji surat anjog, urang baca eta, parsed kana pasangan konci-nilai, nyieun kontak, sarta disimpen dina database.

Ieu SD. Anggap hiji kontak boga sipat Ngaran lengkep, Umur jeung Telepon Kontak. Data ieu dikirimkeun dina surat. Usaha ogé hoyong dukungan supados tiasa gancang nambihan konci énggal pikeun pemetaan sipat éntitas kana pasangan dina awak surat. Bisi batur nyieun typo dina citakan atawa lamun saméméh release perlu urgently ngajalankeun pemetaan ti pasangan anyar, adapting kana format anyar. Teras urang tiasa nambihan korelasi pemetaan énggal salaku datafix murah. Maksudna, conto kahirupan.

Urang ngalaksanakeun, nyieun tés. Gawéna.

Kuring moal nyadiakeun kode teh: aya loba sumber, sarta aranjeunna sadia on GitHub via link di ahir artikel. Anjeun tiasa ngamuat aranjeunna, nyiksa aranjeunna saluareun pangakuan sareng ngukur aranjeunna, sabab bakal mangaruhan dina kasus anjeun. Kuring ngan bakal masihan kodeu dua métode template nu ngabedakeun hydrator, nu sakuduna dituju gancang, ti hydrator nu, nu sakuduna dituju slow.

Logika nyaéta kieu: métode template narima pasangan dihasilkeun ku logika parser dasar. Lapisan LINQ teh parser jeung logika dasar hydrator nu, nu ngajadikeun pamundut ka konteks database na compares konci kalayan pasangan ti parser nu (pikeun fungsi ieu aya kode tanpa LINQ pikeun babandingan). Salajengna, pasangan dialihkeun kana metode hidrasi utama sareng nilai pasangan disetel ka sipat anu saluyu tina éntitas.

"Gancang" (Awalan Gancang dina patokan):

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

Sakumaha urang tiasa tingali, koléksi statik sareng sipat setter dianggo - lambdas kompilasi anu nyauran éntitas setter. Dijieun ku kode di handap ieu:

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

Sacara umum jelas. Urang ngaliwat sipat, nyieun delegasi pikeun aranjeunna nu nelepon setters, sarta simpen aranjeunna. Teras we nelepon lamun perlu.

"Laun" (Awalan Lambat dina patokan):

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

Di dieu urang geuwat bypass sipat sarta nelepon SetValue langsung.

Pikeun kajelasan sareng salaku rujukan, kuring ngalaksanakeun metode naif anu nyerat nilai pasangan korelasina langsung kana widang éntitas. Awalan - Manual.

Ayeuna hayu urang nyandak BenchmarkDotNet sareng pariksa kinerja. Sareng ujug-ujug ... (spoiler - ieu sanés hasil anu leres, detil aya di handap)

Artikel gagal ngeunaan ngagancangkeun réfléksi

Naon anu urang tingali di dieu? Métode anu menangkeun awalan Fast tétéla langkung laun dina ampir sadaya pass tibatan metode anu nganggo awalan Slow. Ieu leres pikeun alokasi sareng laju damel. Di sisi anu sanés, palaksanaan pemetaan anu saé sareng elegan nganggo metode LINQ anu dimaksudkeun pikeun ieu dimana waé, sabalikna, ngirangan produktivitas. Bédana téh urutan. Tren henteu robih kalayan jumlah anu béda. Hijina bédana aya dina skala. Kalayan LINQ éta 4 - 200 kali langkung laun, langkung seueur sampah dina skala anu sami.

diropéa

Abdi henteu percanten kana panon kuring, tapi anu langkung penting, batur sapagawean urang henteu percanten kana panon kuring atanapi kode kuring - Dmitry Tikhonov 0x1000000. Saatos pariksa dua kali solusi kuring, anjeunna terang terang sareng nunjukkeun kasalahan anu kuring lasut kusabab sababaraha parobihan dina palaksanaan, mimiti dugi ka final. Saatos ngalereskeun bug anu dipendakan dina setélan Moq, sadaya hasil murag kana tempatna. Numutkeun hasil retest, trend utama teu robah - LINQ masih mangaruhan kinerja leuwih ti réfléksi. Sanajan kitu, éta nice yén karya kalawan kompilasi éksprési henteu dipigawé sia-sia, sarta hasilna katempo duanana dina alokasi jeung waktu palaksanaan. Peluncuran munggaran, nalika widang statik diinisialisasi, sacara alami langkung laun pikeun metodeu "gancang", tapi kaayaanna robih.

Ieu hasil tés ulang:

Artikel gagal ngeunaan ngagancangkeun réfléksi

Kacindekan: nalika nganggo réfléksi dina perusahaan, teu aya kabutuhan khusus pikeun trik - LINQ bakal langkung ngahakan produktivitas. Nanging, dina metode beban tinggi anu peryogi optimasi, anjeun tiasa nyimpen réfléksi dina bentuk initializer sareng kompiler utusan, anu teras bakal nyayogikeun logika "gancang". Ku cara ieu anjeun tiasa ngajaga kalenturan refleksi sareng laju aplikasi.

Kodeu patokan sayogi di dieu. Saha waé tiasa pariksa deui kecap kuring:
HabraReflectionTests

PS: kodeu dina tés nganggo IoC, sareng dina patokan éta ngagunakeun konstruksi eksplisit. Kanyataanna nyaéta dina palaksanaan ahir kuring neukteuk sagala faktor anu tiasa mangaruhan kinerja sareng ngajantenkeun hasilna ribut.

PPS: Hatur nuhun ka pamaké Dmitry Tikhonov @0x1000000 pikeun manggihan kasalahan kuring dina nyetel Moq, nu mangaruhan pangukuran munggaran. Upami aya anu maca gaduh karma cekap, mangga resep. Lalaki eureun, lalaki nu maca, lalaki nu dua kali dipariksa sarta nunjuk kaluar kasalahan. Jigana ieu pantes hormat jeung simpati.

PPPS: hatur nuhun ka pamaca taliti anu ngagaduhan ka handap gaya sareng desain. Kami pikeun uniformity sarta genah. Diplomasi presentasi daun seueur anu dipikahoyong, tapi kuring nyandak kritikna. Kuring ménta projectile.

sumber: www.habr.com

Tambahkeun komentar