Rövid bevezetés
A System.Collections.Generic.List <T>egy általános gyűjtési osztály a .NET nyelven, amely bármilyen adattípust képes tárolni kényelme és gazdag API-ja miatt, amelyet széles körben használnak a mindennapi életünkben, és nevezhetjük a leggyakrabban használt gyűjteményosztálynak.
A kódírásban gyakran át kell futtatnunk egy <T>Lista gyűjteményt, hogy megszerezzük az elemeket üzleti feldolgozáshoz. Általában nincs sok elem egy készletben, és nagyon gyorsan áthaladhat. De néhány nagy adatfeldolgozás, statisztika, valós idejű számítástechnika <T>stb. esetén hogyan lehet gyorsan áthaladni a tízezrek vagy százezrek adatgyűjtésén? Ezt kell ma megosztanom veled.
Áthaladási mód
Nézzük meg a különböző áthaladási módszerek teljesítményét, és építsük fel a következő teljesítménymérföldet, különböző nagyságrendű gyűjtési áthaladást használva, hogy megtekintsük a különböző módszerek teljesítményét. A kódrészlet így néz ki:
Használd a foreach utasítást
Foreach a leggyakoribb módja a gyűjtemények áthaladásának, ez egy szintaxis-cukor megvalósítása az iterátor mintának, és emiatt is mérföldkőként használják.
Mivel a foreach utasítás szintaxiscukor, a fordító végül a GetEnumerator() és a MoveNext() kódokat hívja egy while hurokkal a funkció megvalósításához. A fordított kód így néz ki:
A MoveNext() metódus megvalósítása biztosítja, hogy ne módosítsák a gyűjteményt az iterációban, és ha a módosítás bekövetkezik, akkor InvalidOperationException kivételt ad ki, és túlcsordulást végez, hogy ellenőrizze, a jelenlegi index hiteles-e, valamint a megfelelő elemet is hozzá kell rendelnie az enumerátorhoz. Jelenlegi attribútum,Szóval valójában a teljesítménye nem a legjobb, a kód részlet így néz ki:
Nézzük meg, hogyan teljesít különböző készletméretekben, és az eredmények így néznek ki:
Látható, hogy különböző méreteknél a lineáris növekedési kapcsolat szükséges az időigényes folyamatban, még akkor is, ha 100w adatot halad át folyamatos logika nélkül, legalább 1 másodpercet igényel.
Használd a ForEach listázás módszerét
Egy másik gyakori mód a <T>Lista használata. ForEach() módszer, amely lehetővé teszi, hogy egy Akció delegált adj át, <T>aki az Akció delegált hívja, miközben az iterált az <T>elemen.
Ez a <T>Lista belső megvalósítási módszere, így közvetlenül hozzáférhet privát tömbökhöz, és elkerülheti a túlcsordulásokat. Elméletileg gyorsnak kellene lennie; De a mi helyzetünkben csak egy üres metódus van, amely nem feltétlenül viselkedik jól egy teljesen inline hívással a foreach metódásra. Az alábbiakban a ForEach metódus forráskódja látható, amely azt mutatja, hogy nincs túlcsordulás ellenőrzése, de továbbra is megtartja a párhuzamos verziószám-ellenőrzést.
Ezen túlmenően, mivel a hívó kódban szükség van delegált objektumot továbbítani a ForEach metódusnak, az ellenőrzi majd, hogy a zárás generáló osztály delegált objektuma mindig üres-e, ha nem, akkor az új Akció<T>(), ahogy az alábbiakban látható:
Nézzük meg, hogyan viszonyul a foreach kulcsszóhoz teljesítmény szempontjából. Az alábbi kép mutatja a benchmark eredményeit:
A teszteredmények alapján 40%-kal lassabb, mint közvetlenül a foreach kulcsszó használata, úgy tűnik, ha nem szükséges, akkor jobb választás közvetlenül foreach használni, szóval van gyorsabb megoldás?
Hurokvándorláshoz
Visszatérve a legrégebbi módszerünkhöz, vagyis a for kulcsszót használjuk a gyűjtemény bejárásához. Ez lehet a legjobban teljesítő átjárási módszer jelenleg is, mert nem igényel olyan redundáns kódot, mint az előzők (bár az indexer is ellenőrizve van a túlcsordulás megelőzése érdekében), és nyilván nem nézi meg a verziószámot, így többszálas környezetben a gyűjtemény változik, és nem kerül kivétel for használatkor. A tesztkód így néz ki:
Nézzük, hogyan alakul.
Úgy tűnik, ez az, ahogy várjuk.A for hurok közvetlen használata 60%-kal gyorsabb, mint az foreach, egy olyan készlet, amely korábban 1 másodpercig tartott a forgatáshoz, most már csak 400 milliszekundumot vesz igénybe. Szóval van gyorsabb megoldás?
Gyűjtemények használataMarshal
A .NET5 után a dotnet közösség bevezette a CollectionsMarshal osztályt a gyűjteményműveletek teljesítményének javítása érdekében. Ez az osztály megvalósítja, hogyan lehet natív tömbökhöz hozzáférni a gyűjteménytípusok (ha láttad az én [. .NET teljesítményoptimalizálás – be kell állítanod a gyűjteménytípusok kezdeti méretét] cikkben, tudod, hogy sok adatstruktúra mögött lévő megvalósítás a tömbök. Így kihagyhat mindenféle észlelést, és közvetlenül hozzáférhet az eredeti tömbhöz, ami a leggyorsabbnak kellene lennie. A kód így néz ki:
Láthatod, hogy a fordító által generált kód nagyon hatékony.
Közvetlen hozzáférés az alapul szolgáló tömbhöz nagyon veszélyes, tudnod kell, mit csinálsz minden kódsorral, és kell elég tesztelésre lenne szükséged. A benchmark eredmények a következők:
HúA CollectionsMarshal használata 79%-kal gyorsabb, mint a foreach használata, de ennek kell lennie a JIT optimalizálásának oka is, nincs nagy különbség a foreach és a for for kulcsszó loop Span használata között.
összefoglalás
Ma arról beszéltem, hogyan lehet gyorsan áthaladni a Lista gyűjteményben, és a legtöbb esetben ajánlott a foreach kulcsszó használatát, amely egyszerre tartalmaz túlcsordulást és többszálas verziószám-vezérlést, ami megkönnyíti a megfelelő kód megírását.
Ha nagy teljesítményre és nagy adatmennyiségre van szükséged, ajánlott közvetlenül a CollectionsMarshal.AsSpan használatát a gyűjtemény átjárásához.
A cikk forráskód linkje:
A hiperlink bejelentkezés látható.
Eredeti link:A hiperlink bejelentkezés látható.
|