Trumpas įvadas
Našumo optimizavimas yra būdas užtikrinti, kad tas pats užklausų skaičius būtų apdorojamas naudojant mažiau išteklių, kurie paprastai yra procesorius arba atmintis, ir, žinoma, operacinės sistemos IO rankenos, tinklo srautas, disko naudojimas ir kt. Tačiau dažniausiai mažiname procesoriaus ir atminties naudojimą. Anksčiau bendrinamas turinys turi tam tikrų apribojimų, jį sunku transformuoti tiesiogiai, šiandien noriu pasidalinti su jumis paprastu metodu, tereikia pakeisti kelis kolekcijos tipus, kad pagerintumėte našumą ir sumažintumėte atminties pėdsaką. Šiandien noriu pasidalinti su jumis klasės biblioteka, taiKlasės biblioteka vadinama Collections.Pooled, Kaip matyti iš pavadinimo, tai yra sutelkta atmintis, kad būtų pasiektas tikslas sumažinti atminties pėdsaką ir GC, ir mes tiesiogiai pamatysime, koks yra jo veikimas, taip pat nuvešime jus pamatyti šaltinio kodą, kodėl jis atneša šiuos našumo patobulinimus.
Kolekcijos.Pooled
Projekto nuoroda:Hipersaito prisijungimas matomas.
Biblioteka pagrįsta System.Collections.Generic klasėmis, kurios buvo modifikuotos, kad būtų galima pasinaudoti naujomis System.Span <T>ir System.Buffers.ArrayPool <T>klasių bibliotekomis, siekiant sumažinti atminties paskirstymą, pagerinti našumą ir užtikrinti didesnį sąveikumą su šiuolaikinėmis API. Collections.Pooled palaiko .NET Standnd 2.0 (.NET Framework 4.6.1+), taip pat palaiko . NET Core 2.1+. Platus vienetų testų ir etalonų rinkinys buvo perkeltas iš CoreFX.
Bendras testų skaičius: 27501. Per: 27501. Nesėkmė: 0. Praleisti: 0. Bandomasis paleidimas buvo sėkmingas. Testo vykdymo laikas: 9,9019 sekundės
Kaip naudoti
Šią biblioteką galite lengvai įdiegti naudodami "Nuget", "NuGet" versiją.
Collections.Pooled bibliotekoje ji įgyvendina sutelktas versijas mūsų dažniausiai naudojamiems rinkinių tipams, kaip parodyta palyginime su .NET vietiniais tipais.
| . .NET vietinis | Kolekcijos.Pooled | Pastaba | | Sąrašas<T> | Sutelktas sąrašas<T> | Bendrosios kolekcijos klasės | | Žodynas<TKey, TValue> | PooledDictionary<TKey, TValue> | Bendroji žodyno klasė | | Maišos rinkinys<T> | Sutelktas rinkinys<T> | Bendrosios maišos rinkimo klasės | | Rietuvė<T> | Rietuvė<T> | Bendrieji rietuvės | | Eilė<T> | PooledQueue<T> | Bendroji grupė |
Naudojant mums reikia pridėti tik atitinkamą . .NET vietinė versija su Collections.Pooled versija, kaip parodyta žemiau esančiame kode:
Tačiau turime pažymėti, kad "Pooled" tipas įgyvendina "IDispose" sąsają, kuri grąžina panaudotą atmintį į telkinį naudojant "Dispose()" metodą, todėl panaudoję "Pooled" kolekcijos objektą turime iškviesti jo metodą "Dispose()". Arba galite tiesiogiai naudoti raktinį žodį var.
Pastaba: Naudokite rinkinio objektą Collections.PooledGeriausia jį atleisti rankiniu būdu, bet nesvarbu, jei jo neišleisite, GC galiausiai jį perdirbs, tačiau jo negalima grąžinti į baseiną ir jis nepasieks atminties taupymo efekto. Kadangi jis pakartotinai naudoja atminties vietą, grąžindamas atminties vietą į telkinį, jis turi apdoroti kolekcijos elementus ir pateikia išvardijimą, vadinamą "ClearMode", apibrėžiamą taip:
Pagal numatytuosius nustatymus galite naudoti numatytąją reikšmę Automatinis, o jei yra specialių našumo reikalavimų, galite naudoti Niekada, žinodami riziką. Nuorodų tipams ir reikšmių tipams, kuriuose yra nuorodų tipų, turime ištuštinti masyvo nuorodą, kai grąžiname atminties vietą į baseiną, jei nebus išvalyta, GC negalės atlaisvinti šios atminties vietos dalies (nes elemento nuorodą visada laikė baseinas), jei tai yra grynas vertės tipas, tada jo negalima ištuštinti, šiame straipsnyje aprašau saugojimo skirtumą tarp nuorodų tipų ir struktūrinių (vertės tipo) masyvų, gryni reikšmių tipai neturi objekto antraštės perdirbimo ir nereikalauja GC įsikišimo.
. .NET našumo optimizavimas – naudokite alternatyvias struktūros klases:Hipersaito prisijungimas matomas.
Našumo palyginimas
Aš nedariau Benchmark vienas, o atvirojo kodo projektų, kuriuos tiesiogiai naudojau, rezultatai buvo 0 daugelio projektų atminties naudojimui, nes sutelkta atmintis nebuvo papildomai paskirstyta.
Sutelktas sąrašas<T>
Ciklas per 2048 elementus, įtrauktus į rinkinį lyginamasis indeksas, . .NET vietiniam sąrašui <T>reikia 110us (pagal faktinius etaloninius rezultatus, milisekundės paveikslėlyje turėtų būti kanceliarinė klaida) ir 263 KB atminties, o PooledList <T>reikia tik 36us ir 0 KB atminties.
PooledDictionary<TKey, TValue>
Įtraukite 10_0000 elementų į žodyną etalono cikle, . .NET vietinis žodynas<TKey, TValue> reikalauja 11 ms ir 13 MB atminties, o PooledDictionary<TKey, TValue> reikalauja tik 7 ms ir 0 MB atminties.
Sutelktas rinkinys<T>
Peržiūrėkite maišos rinkinį etalone pridėkite 10_0000 elementų, . .NET vietiniam "HashSet" <T>reikia 5348 ms ir 2 MB, o "PooledSet" <T>- tik 4723 ms ir 0 MB atminties.
PooledStack<T>
Pereikite per etalono rietuvę, kad pridėtumėte 10_0000 elementų, . .NET vietinis "PooledStack" <T>reikalauja 1079 ms ir 2 MB, o "PooledStack" <T>- tik 633 ms ir 0 MB atminties.
PooledQueue<T>
Pereikite per etalono kilpas, kad į eilę įtrauktumėte 10_0000 elementų, . .NET vietinei <T>"PooledQueue" reikia 681 ms ir 1 MB, o "PooledQueue" <T>– tik 408 ms ir 0 MB atminties.
Scena neišleidžiama rankiniu būdu
Be to, aukščiau minėjome, kad sutelktos kolekcijos tipas turi būti išleistas, tačiau nesvarbu, ar jis nebus išleistas, nes GC bus perdirbtas.
Lyginamojo indekso rezultatai yra tokie:
Išvadą galima padaryti iš aukščiau pateiktų lyginamojo indekso rezultatų.
Išleidus Pooled tipo kolekciją laiku, GC vos suveikia GC ir paskirsto atmintį, iš aukščiau pateiktos diagramos ji paskirsto tik 56 baitus atminties. Net jei telkinio tipo rinkinys nebus išleistas, nes jis paskirsto atmintį iš telkinio, jis vis tiek pakartotinai naudos atmintį ReSize išplėtimo operacijos metu ir praleis GC paskirstymo atminties inicijavimo veiksmą, kuris yra gana greitas. Lėčiausias yra naudoti įprastą rinkimo tipą, kiekviena "ReSize" išplėtimo operacija turi būti taikoma naujai atminties vietai, o GC taip pat turi susigrąžinti ankstesnę atminties vietą.
Principų analizė
Jei perskaitėte mano ankstesnį tinklaraščio įrašą, turėtumėte nustatyti pradinį kolekcijos tipų dydį ir išanalizuoti C# žodyno įgyvendinimo principą, galite žinoti, kad .NET BCL kūrėjai naudoja pagrindines šių pagrindinių rinkimo tipų duomenų struktūras kaip didelio našumo atsitiktinės prieigos masyvus, paimkime sąrašą <T>kaip pavyzdį.
Sukurkite naują masyvą pridėtiems elementams saugoti. Jei masyve nepakanka vietos, išplėtimo operacija suaktyvinama, kad būtų prašoma dvigubai didesnės vietos. Konstruktoriaus kodas yra toks, ir jūs galite pamatyti, kad tai yra bendras masyvas, sukurtas tiesiogiai:
Taigi, jei norite sutelkti atmintį, jums tereikia pakeisti vietą, kur klasės bibliotekoje naudojama nauja raktažodžio programa, kad būtų galima naudoti sutelktą programą. Čia dalinuosi juo su jumis. NET BCL yra tipas, vadinamas ArrayPool, kuris suteikia daugkartinio naudojimo bendrųjų egzempliorių masyvo išteklių telkinį, kuris gali būti naudojamas siekiant sumažinti GC spaudimą ir pagerinti našumą dažno masyvo kūrimo ir sunaikinimo atveju.
Pagrindinis mūsų Pooled tipo sluoksnis yra naudoti ArrayPool išteklių telkiniams bendrinti, o iš jo konstruktoriaus matome, kad pagal numatytuosius nustatymus jis naudoja ArrayPool<T>. Bendrai priskiriant masyvo objektus, ir, žinoma, taip pat galite sukurti savo ArrayPool, kad galėtumėte jį naudoti.
Be to, atliekant talpos reguliavimo operaciją (išplėtimą), senas masyvas grąžinamas į gijų telkinį, o naujas masyvas taip pat įsigyjamas iš telkinio.
Be to, autorius naudoja "Span", kad optimizuotų API, pvz., "Add" ir "Insert", kad užtikrintų geresnį laisvosios prieigos našumą. Be to, pridėta TryXXX serijos API, todėl galite ja naudotis patogiau. Pavyzdžiui, "List" <T>klasėje <T>yra iki 170 modifikacijų, palyginti su "PooledList".
suvestinė
Faktiškai naudodamiesi internetu, galime pakeisti vietinį kolekcijos tipą "Pooled" pateiktu kolekcijos tipu, o tai labai naudinga mažinant atminties naudojimą ir P95 delsą. Be to, net jei pamiršite jį išleisti, našumas nebus daug blogesnis nei naudojant vietinį kolekcijos tipą. Žinoma, geriausias įprotis yra laiku jį paleisti.
Originalus:Hipersaito prisijungimas matomas.
|