Dit artikel is een spiegelartikel van machinevertaling, klik hier om naar het oorspronkelijke artikel te gaan.

Bekijken: 6317|Antwoord: 3

[Bron] [Draai]. NET-prestatieoptimalisaties - doorloop snel lijstcollecties

[Link kopiëren]
Geplaatst op 28-8-2022 20:51:16 | | | |
Korte introductie

System.Collections.Generic.List <T>is een generieke verzamelingsklasse in .NET, die elk type data kan opslaan vanwege het gemak en de rijke API, die veel wordt gebruikt in ons dagelijks leven en kan worden beschouwd als de meest gebruikte verzamelklasse.

Bij het schrijven van code moeten we vaak door een Lijstcollectie itereren <T>om de elementen daarin te verkrijgen voor bepaalde zakelijke verwerking. Normaal gesproken zijn er niet veel elementen binnen een set en is het heel snel om te doorlopen. Maar voor wat big data-verwerking, statistiek, realtime computing, enzovoort<T>, hoe kun je dan snel de lijst van tienduizenden of honderdduizenden data doorlopen? Dat is wat ik vandaag met je moet delen.

Traverseringsmodus

Laten we eens kijken naar de prestaties van verschillende doorloopmethoden en de volgende prestatiebenchmark opstellen, waarbij we verschillende orde van grootte verzameling doorlopen gebruiken om de prestaties van verschillende methoden te zien. Het codefragment ziet er zo uit:

Gebruik de foreach-stelling

Foreach is de meest gebruikelijke manier waarop we collecties doorlopen, het is een syntaxis-suikerimplementatie van het iteratorpatroon, en het wordt ook gebruikt als benchmark voor deze periode.

Omdat de foreach-instructie een syntaxissuiker is, roept de compiler uiteindelijk GetEnumerator() en MoveNext() aan met een while-lus om de functionaliteit te implementeren. De gecompileerde code ziet er zo uit:



De implementatie van de MoveNext()-methode zorgt ervoor dat er geen andere threads zijn die de collectie wijzigen tijdens de iteratie, en als de wijziging plaatsvindt, wordt er een InvalidOperationException-uitzondering gegooid, en wordt er een overflow-controle uitgevoerd om te controleren of de huidige index legitiem is, en moet het ook het bijbehorende element aan de enumerator worden toegewezen. Huidig attribuut,Dus in feite is de prestatie niet de beste, het codefragment ziet er zo uit:



Laten we eens kijken hoe het presteert over verschillende setgroottes, en de resultaten zien er als volgt uit:



Het is te zien dat bij verschillende groottes de lineaire groeirelatie van het tijdrovende proces vereist is; zelfs als het 100W aan data doorloopt zonder enige verwerkingslogica, het kost minstens 1 seconden.

Gebruik de ForEach-methode van List

Een andere veelgebruikte manier is het gebruik van Lijst<T>. ForEach()-methode, waarmee je een <T>Actie-delegate kunt doorgeven, die de Actie-delegate aanroept terwijl deze door het element iterert<T>.

Het is een <T>interne implementatiemethode van List, zodat het direct toegang kan krijgen tot private arrays en overflowcontroles kan vermijden. In theorie zou het snel moeten zijn; Maar in ons scenario is er maar één lege methode, die zich mogelijk niet goed gedraagt met een volledig inline aanroep naar de foreach-methode. Hieronder staat de broncode van de ForEach-methode, die laat zien dat er geen overflowcontrole is, maar dat er nog steeds gelijktijdige versienummercontrole wordt behouden.



Bovendien, omdat het nodig is om een delegate door te geven aan de ForEach-methode, zal in de aanroepcode gecontroleerd worden of het delegate-object in de closure generation class elke keer leeg is, en zo niet, nieuwe Action<T>(), zoals hieronder weergegeven:



Laten we eens kijken hoe het zich verhoudt tot het foreach-keyword qua prestaties. De volgende afbeelding toont de resultaten van de benchmark:



Afgaande op de testresultaten is het 40% langzamer dan het directe gebruik van het foreach-zoekwoord; het lijkt erop dat als het niet nodig is, het beter is om het direct voor for te gebruiken, dus is er een snellere manier?

voor lusdoorloop

Terug naar onze oudste manier, namelijk het for sleutelwoord gebruiken om door de collectie te lopen. Het zou op dit moment de best presterende traversalmethode moeten zijn, omdat het geen redundante code vereist zoals de vorige (hoewel de indexer ook wordt gecontroleerd om overflows te voorkomen), en uiteraard controleert hij het versienummer niet, dus in een multithreaded omgeving wordt de collectie aangepast en wordt er geen uitzondering gegooid bij het gebruik van for. De testcode ziet er als volgt uit:

Laten we zien hoe het afloopt.



Dit lijkt te zijn hoe we het verwachten.Het direct gebruiken van de for-lus is 60% sneller dan foreach, een set die vroeger 1 seconde kostte om te doorkruisen, nu slechts 400 milliseconden kost. Is er dus een snellere manier?

Gebruik CollectiesMarshal

Na .NET5 implementeerde de dotnet-gemeenschap de CollectionsMarshal-klasse om de prestaties van verzamelingsoperaties te verbeteren. Deze klasse implementeert hoe je toegang krijgt tot native arrays van verzamelingstypes (als je mijn [. .NET Performance Optimization - Je moet de initiële grootte instellen voor collectietypes] artikel, je weet dat de onderliggende implementatie van veel datastructuren arrays zijn). Dus hij kan allerlei detecties overslaan en direct toegang krijgen tot de originele array, wat het snelst zou moeten zijn. De code ziet er zo uit:

Je ziet dat de code die door de compiler wordt gegenereerd erg efficiënt is.



Directe toegang tot de onderliggende array is erg gevaarlijk, je moet weten wat je met elke regel code doet en voldoende testen hebben. De benchmarkresultaten zijn als volgt:



WauwHet gebruik van CollectionsMarshal is 79% sneller dan het gebruik van foreach, maar het zou de reden moeten zijn voor JIT-optimalisatie, er is geen groot verschil tussen het gebruik van foreach en voor keyword loop Span.

samenvatting

Vandaag heb ik met jullie gesproken over hoe je snel door de Lijstcollectie kunt lopen, en in de meeste gevallen wordt aanbevolen om het foreach-zoekwoord te gebruiken, dat zowel overflowcontrole als multithreaded versienummerbesturing heeft, wat het makkelijker maakt om de juiste code te schrijven.

Als je hoge prestaties en grote datavolumes nodig hebt, wordt aanbevolen om direct CollectionsMarshal.AsSpan te gebruiken om de collectie te doorlopen.

Broncode link van dit artikel:

De hyperlink-login is zichtbaar.

Originele link:De hyperlink-login is zichtbaar.





Vorig:Gedetailleerde uitleg van de RabbitMQ AMQP-berichtarchitectuur
Volgend:Netwerkkabelkristalkop T568A en T568B standaard en verschil
Geplaatst op 4-9-2022 22:15:52 |
Leer leren
Geplaatst op 2022-9-8 10:33:05 |
Leer leren
Geplaatst op 27-6-2023 22:39:13 |
Hallo 12306 Kunt u mij een privébericht sturen met gegevens
Disclaimer:
Alle software, programmeermaterialen of artikelen die door Code Farmer Network worden gepubliceerd, zijn uitsluitend bedoeld voor leer- en onderzoeksdoeleinden; De bovenstaande inhoud mag niet worden gebruikt voor commerciële of illegale doeleinden, anders dragen gebruikers alle gevolgen. De informatie op deze site komt van het internet, en auteursrechtconflicten hebben niets met deze site te maken. Je moet bovenstaande inhoud volledig van je computer verwijderen binnen 24 uur na het downloaden. Als je het programma leuk vindt, steun dan de echte software, koop registratie en krijg betere echte diensten. Als er sprake is van een inbreuk, neem dan contact met ons op via e-mail.

Mail To:help@itsvse.com