Acest articol este un articol oglindă al traducerii automate, vă rugăm să faceți clic aici pentru a sări la articolul original.

Vedere: 6317|Răspunde: 3

[Sursă] [Întoarce]. Optimizări de performanță NET - parcurgerea rapidă a colecțiilor de liste

[Copiază linkul]
Postat la 28-08-2022 20:51:16 | | | |
Scurtă introducere

System.Collections.Generic.List <T>este o clasă generică de colecție în .NET, care poate stoca orice tip de date datorită comodității și API-ului său bogat, folosit pe scară largă în viața noastră de zi cu zi și poate fi considerat cea mai utilizată clasă de colecție.

În scrierea codului, adesea trebuie să iterăm printr-o <T>colecție de liste pentru a obține elementele din ea pentru procesarea afacerii. De obicei, nu sunt multe elemente într-un set și este foarte rapid de parcurs. Dar pentru unele procesări big data, statistică, calcul în timp real etc<T>., cum să parcurgi rapid lista de colecții de zeci de mii sau sute de mii de date? Asta trebuie să vă spun astăzi.

Modul de traversare

Să aruncăm o privire asupra performanței diferitelor metode de traversare și să construim următorul benchmark de performanță, folosind traversarea colecțiilor de ordine de mărime pentru a vedea performanța diferitelor metode. Fragmentul de cod arată astfel:

Folosește instrucțiunea foreach

Foreach este cea mai comună modalitate prin care parcurgem colecții, este o implementare syntax sugar a modelului iterator și este folosit și ca benchmark pentru această perioadă.

Deoarece instrucțiunea foreach este un sintax sugar, compilatorul apelează în cele din urmă GetEnumerator() și MoveNext() cu o buclă while pentru a implementa funcționalitatea. Codul compilat arată astfel:



Implementarea metodei MoveNext() va asigura că nu vor exista alte fire care să modifice colecția în iterație, iar dacă modificarea are loc, va genera o excepție InvalidOperationException și va avea o verificare suplimentară pentru a verifica dacă indexul curent este legitim și trebuie să atribuie elementul corespunzător enumeratorului. Atributul actual,Așadar, de fapt, performanța sa nu este cea mai bună, fragmentul de cod arată astfel:



Să aruncăm o privire asupra modului în care se comportă la diferite dimensiuni de set, iar rezultatele arată astfel:



Se poate observa că, în cazul unor dimensiuni diferite, este necesară relația de creștere liniară a procesului care consumă mult timp, chiar dacă parcurge 100w de date fără nicio logică de procesare, durează cel puțin 1 secundă.

Folosește metoda ForEach de listă

O altă metodă comună este să folosești <T>Listă. ForEach(), care îți permite să treci un delegat de Acțiune<T>, care va chema delegatul de Acțiune pe măsură ce itera prin element<T>.

Este o <T>metodă internă de implementare a List, astfel încât poate accesa direct tablouri private și poate evita verificările de debordare. Teoretic, ar trebui să fie rapid; Dar în scenariul nostru există o singură metodă goală, care s-ar putea să nu se comporte bine cu un apel complet inline la metoda foreach. Mai jos este codul sursă al metodei ForEach care arată că nu are verificare a overflow-ului, dar păstrează totuși verificarea concurentă a numărului de versiune.



În plus, deoarece este necesar să se transmită un delegat către metoda ForEach în codul de apel, acesta va verifica dacă obiectul delegat din clasa de generare a închiderii este gol de fiecare dată și, dacă nu, noul Action<T>(), așa cum se arată mai jos:



Să vedem cum se compară cu cuvântul cheie foreach în ceea ce privește performanța. Imaginea următoare arată rezultatele benchmark-ului:



Judecând după rezultatele testelor, este cu 40% mai lent decât să folosești direct cuvântul-cheie foreach, pare că dacă nu este necesar, este o alegere mai bună să folosești foreach direct, deci există o metodă mai rapidă?

pentru traversarea buclei

Revenind la cea mai veche metodă a noastră, care este să folosim cuvântul cheie for pentru a parcurge această colecție. Ar trebui să fie cea mai performantă metodă de traversare în acest moment, pentru că nu necesită cod redundant ca cele anterioare (deși indexerul este verificat și pentru a preveni depășirea depășirilor), iar evident nu verifică numărul versiunii, deci într-un mediu multithreaded colecția se schimbă și nu va exista nicio excepție la folosirea for. Codul de test arată astfel:

Să vedem cum iese.



Se pare că așa ne așteptăm.Folosirea buclei for direct este cu 60% mai rapidă decât foreach, un set care înainte dura 1 secundă să fie parcurs, acum durează doar 400 de milisecunde. Deci există o metodă mai rapidă?

Folosește CollectionsMarshal

După .NET5, comunitatea dotnet a implementat clasa CollectionsMarshal pentru a îmbunătăți performanța operațiunilor de colectare. Această clasă implementează modul de accesare a array-urilor native de tipuri de colecții (dacă ai văzut [. .NET Performance Optimization - Ar trebui să setezi dimensiunea inițială pentru tipurile de colecție], știi că implementarea de bază a multor structuri de date este array-ul). Astfel, poate sări peste tot felul de detectări și poate accesa direct array-ul original, care ar trebui să fie cel mai rapid. Codul arată astfel:

Poți vedea că codul generat de compilator este foarte eficient.



Accesul direct la array-ul de bază este foarte periculos, trebuie să știi ce faci cu fiecare linie de cod și să ai suficiente testări. Rezultatele reperelor sunt următoarele:



WowFolosirea CollectionsMarshal este cu 79% mai rapidă decât folosirea foreach, dar ar trebui să fie motivul optimizării JIT, nu există o diferență mare între folosirea foreach și bucla pentru cuvinte-cheie Span.

rezumat

Astăzi v-am vorbit despre cum să parcurgeți rapid colecția List și, în cele mai multe cazuri, este recomandat să folosiți cuvântul-cheie foreach, care are atât verificarea overflow-ului, cât și control multi-threaded al numărului de versiune, ceea ce ne poate ajuta să scriem codul corect.

Dacă ai nevoie de performanțe ridicate și volume mari de date, este recomandat să folosești for, și CollectionsMarshal.AsSpan direct pentru a parcurge colecția.

Link către codul sursă al acestui articol:

Autentificarea cu hyperlink este vizibilă.

Link original:Autentificarea cu hyperlink este vizibilă.





Precedent:Explicație detaliată a arhitecturii mesajelor AMQP RabbitMQ
Următor:Cap de cristal pentru cablu de rețea T568A și T568B standard și diferențe
Postat la 2022-9-4 22:15:52 |
Învață să înveți
Postat la 2022-9-8 10:33:05 |
Învață să înveți
Postat la 2023-6-27 22:39:13 |
Salut 12306 Poți să-mi trimiți un mesaj privat cu datele
Disclaimer:
Tot software-ul, materialele de programare sau articolele publicate de Code Farmer Network sunt destinate exclusiv scopurilor de învățare și cercetare; Conținutul de mai sus nu va fi folosit în scopuri comerciale sau ilegale, altfel utilizatorii vor suporta toate consecințele. Informațiile de pe acest site provin de pe Internet, iar disputele privind drepturile de autor nu au legătură cu acest site. Trebuie să ștergi complet conținutul de mai sus de pe calculatorul tău în termen de 24 de ore de la descărcare. Dacă îți place programul, te rugăm să susții software-ul autentic, să cumperi înregistrarea și să primești servicii autentice mai bune. Dacă există vreo încălcare, vă rugăm să ne contactați prin e-mail.

Mail To:help@itsvse.com