Lühike sissejuhatus
System.Collections.Generic.List on üldine <T>kogumisklass .NET-is, mis suudab salvestada igat tüüpi andmeid tänu oma mugavusele ja rikkalikule API-le, mida kasutatakse laialdaselt meie igapäevaelus ning mida võib pidada enim kasutatavaks kogumisklassiks.
Koodi kirjutamisel tuleb sageli <T>loendikogu läbi sirvida, et saada selle elemendid äriprotsesside jaoks. Tavaliselt pole komplektis palju elemente ja seda on väga kiire läbida. Aga mõne suurandmete töötlemise, statistika, reaalajas arvutuse <T>jms puhul, kuidas kiiresti läbida kümnete tuhandete või sadade tuhandete andmete kogumist? Just seda pean täna teiega jagama.
Liikumisrežiim
Vaatame erinevate läbimismeetodite jõudlust ja koostame järgmise jõudluse võrdluspunkti, kasutades erineva suurusjärgu kogumise läbimist, et näha erinevate meetodite jõudlust. Koodilõik näeb välja selline:
Kasuta foreach lauset
foreach on kõige levinum viis, kuidas me kogumeid läbime, see on iteraatori mustri süntaksi suhkru rakendus ning seda kasutatakse ka selle aja võrdluspunktina.
Kuna foreach lause on süntaksisuhkur, kutsub kompilaator lõpuks GetEnumerator() ja MoveNext() koos while-tsükliga, et funktsionaalsust rakendada. Kompileeritud kood näeb välja selline:
MoveNext() meetodi rakendus tagab, et iteratsioonis ei muuda teisi lõime, ning kui muudatus toimub, lisatakse InvalidOperationException erik ning ületäitumise kontroll, et kontrollida, kas praegune indeks on usaldusväärne, ning peab määrama vastava elemendi loendajale. Praegune omadus,Seega pole selle jõudlus tegelikult parim, koodilõik näeb välja selline:
Vaatame, kuidas see erinevates komplektide suurustes toimib, ja tulemused näevad välja järgmised:
Erineva suurusega puhul on vaja ajamahuka protsessi lineaarset kasvusuhet, isegi kui läbitakse 100w andmeid ilma töötlemisloogikata, võtab see vähemalt 1 sekundit.
Kasuta loendamise ForEach meetodit
Teine levinud viis on kasutada <T>Listi. ForEach() meetod, mis võimaldab edasi anda <T>tegevusdelegaati, kes kutsub tegevusdelegaati, kui see elementi <T>läbib.
See on <T>Listi sisemine rakendusmeetod, mistõttu pääseb otse ligi privaatsetele massiividele ja väldib ületäitumise kontrolle. Teoorias peaks see olema kiire; Aga meie stsenaariumis on ainult üks tühi meetod, mis ei pruugi hästi käituda täielikult sisemise foreach meetodi kutsega. Allpool on ForEach meetodi lähtekood, mis näitab, et ületäitumise kontrolli puudub, kuid see säilitab samaaegse versiooninumbri kontrolli.
Lisaks, kuna on vajalik edastada delegaat ForEach meetodile, kontrollib see kutsekoodis, kas sulgemisgeneratsiooni klassi delegeeritud objekt on iga kord tühi, ja kui mitte, siis uus Action<T>(), nagu allpool näidatud:
Vaatame, kuidas see võrreldes foreach märksõnaga jõudluse poolest on. Järgmine pilt näitab võrdlustesti tulemusi:
Testitulemuste põhjal on see 40% aeglasem kui otse foreach märksõna kasutamine, tundub, et kui see pole vajalik, on parem kasutada foreach otse, nii et kas on olemas kiirem viis?
silmuse läbimiseks
Tagasi meie vanima viisi juurde, milleks on kasutada märksõna for kogu läbimiseks. See peaks hetkel olema kõige paremini toimiv läbimismeetod, sest see ei nõua mingit korduvkoodi nagu varasemad (kuigi indekseerija kontrollitakse ka ületäitumise vältimiseks), ja loomulikult ei kontrolli see versiooninumbrit, nii et mitmelõimelises keskkonnas muudetakse kogumik ja for-i kasutamisel erandeid ei ole. Testkood näeb välja selline:
Vaatame, kuidas see välja kukub.
Tundub, et see on just see, mida me ootame.For-tsükli otsene kasutamine on 60% kiirem kui foreach, komplekt, mis varem võttis läbimiseks ühe sekundi, võtab nüüd vaid 400 millisekundit. Kas on olemas kiirem viis?
Kogude kasutamineMarssal
Pärast .NET5 rakendust rakendas dotnet-kogukond CollectionsMarshal klassi, et parandada kogumistoimingute jõudlust. See klass rakendab, kuidas pääseda ligi kogumitüüpide natiivsetele massiividele (kui olete näinud minu [. .NET jõudluse optimeerimine – peaksite määrama algsuuruse kogumitüüpide jaoks] artiklis, teate, et paljude andmestruktuuride aluseks on massiivid. Seega saab ta vahele jätta kõikvõimalikud tuvastused ja pääseda otse ligi algsele massiivile, mis peaks olema kõige kiirem. Kood näeb välja selline:
Näete, et kompilaatori genereeritud kood on väga tõhus.
Otsene ligipääs aluseks olevale massiivile on väga ohtlik, pead teadma, mida iga koodireaga teed, ja tegema piisavalt testimist. Võrdlustulemused on järgmised:
VauCollectionsMarshali kasutamine on 79% kiirem kui foreach, kuid see peaks olema põhjus JIT-i optimeerimiseks, foreach ja for keyword loop span kasutamisel pole suurt vahet.
Kokkuvõte
Täna rääkisin teiega, kuidas kiiresti Listi kogus liikuda, ja enamasti soovitatakse kasutada foreach märksõna, millel on nii ülevoolu kontroll kui ka mitmelõimeline versiooninumbri kontroll, mis teeb õige koodi kirjutamise lihtsamaks.
Kui vajad suurt jõudlust ja suuri andmemahtu, soovitatakse seda kasutada CollectionsMarshal.AsSpan otse kogu läbimiseks.
Selle artikli lähtekoodi link:
Hüperlingi sisselogimine on nähtav.
Originaallink:Hüperlingi sisselogimine on nähtav.
|