Lyhyt johdanto
System.Collections.Generic.List <T>on geneerinen kokoelmaluokka .NET:ssä, joka voi tallentaa minkä tahansa tyyppisiä tietoja kätevyytensä ja monipuolisen API:n ansiosta, jota käytetään laajasti arjessamme ja jota voidaan pitää eniten käytettynä kokoelmaluokkana.
Koodin kirjoittamisessa meidän täytyy usein käydä läpi <T>listakokoelmaa saadaksemme sen elementit liiketoimintaprosessointia varten. Normaalisti setissä ei ole montaa elementtiä ja sen läpikäyminen on hyvin nopeaa. Mutta joidenkin big data -käsittelyn, tilastojen, reaaliaikaisen laskennan ym<T>. kohdalla, miten nopeasti selata kymmenien tuhansien tai satojen tuhansien datan listakokoelmaa? Se on se, mitä haluan jakaa kanssanne tänään.
Kulkutila
Tarkastellaan eri kulkumenetelmien suorituskykyä ja rakennetaan seuraava suorituskykymittari, jossa käytetään eri kertaluokkia keräyskulkua eri menetelmien suorituskyvyn näkemiseksi. Koodipätkä näyttää tältä:
Käytä foreach -lausetta
foreach on yleisin tapa, jolla käymme kokoelmia läpi, se on syntaksisokerin toteutus iteraattorimallille, ja sitä käytetään myös vertailuarvona tälle ajalle.
Koska forach-lause on syntaksisokeri, kääntäjä kutsuu lopulta GetEnumerator() ja MoveNext() while-silmukalla toteuttaakseen toiminnallisuuden. Käännetty koodi näyttää tältä:
MoveNext()-metodin toteutus varmistaa, ettei kokoelmaa muokkaa muita säikeitä iteraatiossa, ja jos muutos tapahtuu, se heittää InvalidOperationException-poikkeuksen, ja sillä on ylivuototarkistus tarkistamaan nykyisen indeksin laillisuus, ja sen täytyy myös liittää vastaava alkio luetelijalle. Nykyinen ominaisuus,Joten itse asiassa sen suorituskyky ei ole paras, koodipätkä näyttää tältä:
Katsotaanpa, miten se toimii eri kokoisissa, ja tulokset näyttävät tältä:
On havaittavissa, että eri kokojen tapauksessa aikaa vievän prosessin lineaarinen kasvusuhde vaaditaan, vaikka se kulkisi 100w dataa ilman minkäänlaista käsittelylogiikkaa, se vie vähintään 1 sekuntia.
Käytä ForEach -listausmenetelmää
Toinen yleinen tapa on käyttää <T>Listaa. ForEach()-metodi, jonka avulla voit välittää Action <T>Delegate, joka kutsuu Action Delegate sen iteroidessaan <T>elementtiä.
Se on <T>Listin sisäinen toteutusmenetelmä, joten se voi suoraan päästä yksityisiin taulukoihin ja välttää ylivuototarkistukset. Teoriassa sen pitäisi olla nopeaa; Mutta meidän skenaariossamme on vain yksi tyhjä metodi, joka ei välttämättä toimi hyvin täysin inline-kutsulla forach-metodiin. Alla on ForAchify-metodin lähdekoodi, joka osoittaa, ettei siinä ole ylivuototarkistusta, mutta se säilyttää silti samanaikaisen versionumeron tarkistuksen.
Lisäksi, koska ForAchify-metodiin täytyy siirtää delegaatti, kutsukoodissa tarkistetaan, onko sulkeutumisgeneraattoriluokan delegaattiobjekti tyhjä joka kerta, ja jos ei, uusi Action<T>(), kuten alla on esitetty:
Katsotaanpa, miten se vertautuu forach-avainsanaan suorituskyvyn suhteen. Seuraava kuva näyttää vertailutulokset:
Testitulosten perusteella se on 40 % hitaampaa kuin foreach -avainsanan suora käyttö, ja vaikuttaa siltä, että jos se ei ole tarpeen, on parempi käyttää foreach suoraan, joten onko olemassa nopeampaa tapaa?
silmukan läpikulkua varten
Palatakseni vanhimpaan tapaamme, eli käyttää for-avainsanaa kokoelman läpikäymiseen. Sen pitäisi olla tällä hetkellä parhaiten toimiva läpikäyntimenetelmä, koska se ei vaadi päällekkäistä koodia kuten aiemmat (vaikka indeksointi tarkistetaan myös ylivuotojen estämiseksi), eikä tietenkään se tarkista versionumeroa, joten monisäikeisessä ympäristössä kokoelma muuttuu, eikä for:n käytössä ole poikkeuksia. Testikoodi näyttää tältä:
Katsotaan, miten se käy.
Näyttää siltä, että tämä on juuri se, mitä odotamme.For-silmukan suora käyttö on 60 % nopeampaa kuin foreach, sarja, joka aiemmin kesti sekunnin liikkua, vie nyt vain 400 millisekuntia. Onko siis olemassa nopeampaa tapaa?
KäyttökokoelmatMarshal
.NET5:n jälkeen dotnet-yhteisö otti käyttöön CollectionsMarshal-luokan parantaakseen kokoelmatoimintojen suorituskykyä. Tämä luokka toteuttaa, miten päästä käsiksi kokoelmatyyppien natiiviryhmiin (jos olet nähnyt [. .NET Performance Optimization – Sinun tulisi asettaa kokoelmatyyppien alkuperäinen koko] artikkelissa, tiedät, että monien tietorakenteiden taustalla oleva toteutus on taulukot. Näin se voi ohittaa kaikenlaiset havainnot ja päästä suoraan alkuperäiseen taulukkoon, jonka pitäisi olla nopein. Koodi näyttää tältä:
Näet, että kääntäjän tuottama koodi on erittäin tehokasta.
Suora pääsy taustalla olevaan taulukkoon on erittäin vaarallista, sinun täytyy tietää, mitä teet jokaisella koodirivillä ja tehdä riittävästi testejä. Vertailutulokset ovat seuraavat:
VauCollectionsMarshalin käyttö on 79 % nopeampaa kuin foreach, mutta sen pitäisi olla syy JIT-optimointiin, ei ole suurta eroa käyttää foreach ja for for keyword loop Span.
yhteenveto
Tänään puhuin teille siitä, miten Listan kokoelmaa voi nopeasti läpi käydä, ja useimmissa tapauksissa suositellaan käyttämään foreach -avainsanaa, jossa on sekä ylivuodon tarkistus että monisäikeinen versionumeroiden hallinta, mikä helpottaa oikean koodin kirjoittamista.
Jos tarvitset korkean suorituskyvyn ja suuria tietomääriä, suositellaan käyttämään sitä suoraan CollectionsMarshal.AsSpan-palvelua kokoelman läpikäymiseen.
Tämän artikkelin lähdekoodilinkki:
Hyperlinkin kirjautuminen on näkyvissä.
Alkuperäinen linkki:Hyperlinkin kirjautuminen on näkyvissä.
|