Questo articolo è un articolo speculare di traduzione automatica, clicca qui per saltare all'articolo originale.

Vista: 6317|Risposta: 3

[Fonte] [Gira]. Ottimizzazioni delle prestazioni NET - attraversa rapidamente le collezioni di liste

[Copiato link]
Pubblicato il 28-08-2022 20:51:16 | | | |
Breve introduzione

System.Collections.Generic.List <T>è una classe di raccolta generica in .NET, che può memorizzare qualsiasi tipo di dato grazie alla sua comodità e alla ricchezza API, ampiamente utilizzata nella nostra vita quotidiana e può essere considerata la classe di raccolta più utilizzata.

Nella scrittura di codice, spesso dobbiamo iterare attraverso una <T>collezione List per ottenere gli elementi in essa per alcune elaborazioni aziendali. Normalmente, non ci sono molti elementi all'interno di un set ed è molto veloce da attraversare. Ma per alcuni big data, statistica, calcolo in tempo reale, ecc<T>., come si può rapidamente attraversare la raccolta di liste di decine di migliaia o centinaia di migliaia di dati? È questo che devo condividere con voi oggi.

Modalità di spostamento

Diamo un'occhiata alle prestazioni dei diversi metodi di traversa e costruiamo il seguente benchmark di prestazione, utilizzando diversi ordini di grandezza di raccolte di attraversamento per vedere le prestazioni di diversi metodi. Il snippet di codice appare così:

Usa l'istruzione foreach

Foreach è il modo più comune in cui attraversiamo le collezioni, è un'implementazione syntax sugar del pattern iterator ed è anche usato come benchmark per questo periodo.

Poiché l'istruzione foreach è uno zucchero sintassi, il compilatore alla fine chiama GetEnumerator() e MoveNext() con un ciclo while per implementare la funzionalità. Il codice compilato appare così:



L'implementazione del metodo MoveNext() garantirà che non ci saranno altri thread che modifichino la collezione nell'iterazione e, se la modifica avverrà, verrà inviata un'eccezione InvalidOperationException, avrà un controllo di overflow per verificare se l'indice corrente è legittimo, e deve anche assegnare l'elemento corrispondente all'enumeratore. Attributo attuale,Quindi, in realtà, le sue prestazioni non sono le migliori, il frammento di codice appare così:



Diamo un'occhiata a come si comporta tra diverse dimensioni di set, e i risultati sono questi:



Si può vedere che, nel caso di dimensioni diverse, è necessaria la relazione di crescita lineare del processo che richiede tempo, anche se attraversa 100w di dati senza alcuna logica di elaborazione, richiede almeno 1 secondo.

Usa il metodo ForEach di List

Un altro modo comune è usare List<T>. ForEach(), che ti permette di passare un <T>delegato Azione, che chiamerà il delegato Azione mentre itera attraverso l'elemento<T>.

È un <T>metodo di implementazione interna di List, quindi può accedere direttamente agli array privati ed evitare controlli di overflow. In teoria, dovrebbe essere veloce; Ma nel nostro scenario c'è un solo metodo vuoto, che potrebbe non comportarsi bene con una chiamata completamente inline al metodo foreach. Di seguito è riportato il codice sorgente del metodo ForEach che mostra che non dispone di overflow checking, ma mantiene comunque il controllo concorrente dei numeri di versione.



Inoltre, poiché è necessario passare un delegato al metodo ForEach nel codice di chiamata, verificherà se l'oggetto delegato nella classe di generazione di chiusura è vuoto ogni volta, e in caso contrario, nuova Action<T>(), come mostrato di seguito:



Vediamo come si confronta con la parola chiave foreach in termini di prestazioni. L'immagine seguente mostra i risultati del benchmark:



A giudicare dai risultati del test, è il 40% più lento rispetto all'uso diretto della parola chiave foreach; sembra che se non è necessario, sia una scelta migliore usarlo direttamente, quindi esiste un modo più veloce?

per la percorrenza dell'anello

Tornando al nostro metodo più antico, che è usare la parola chiave for per attraversare la collezione. Dovrebbe essere il metodo di attraversamento con le migliori prestazioni al momento, perché non richiede codice ridondante come i precedenti (anche se l'indicizzatore viene controllato per prevenire overflow), e ovviamente non controlla il numero di versione, quindi in un ambiente multithread la collezione viene modificata e non verrà fatta alcuna eccezione quando si usa for. Il codice di test appare così:

Vediamo come va.



Sembra che sia così che ci aspettiamo.Usare direttamente il ciclo for è il 60% più veloce rispetto a foreach, un set che prima richiedeva 1 secondo per essere attraversato, ora richiede solo 400 millisecondi. Quindi esiste un modo più veloce?

Usa le collezioniMaresciallo

Dopo .NET5, la comunità dotnet ha implementato la classe CollectionsMarshal per migliorare le prestazioni delle operazioni di raccolta. Questa classe implementa come accedere agli array nativi dei tipi di collezione (se avete visto il mio [. Ottimizzazione delle prestazioni .NET - Dovresti impostare la dimensione iniziale per i tipi di collezione], sai che l'implementazione sottostante di molte strutture dati sono gli array). Quindi può saltare ogni tipo di rilevamento e accedere direttamente all'array originale, che dovrebbe essere il più veloce. Il codice appare così:

Puoi vedere che il codice generato dal compilatore è molto efficiente.



L'accesso diretto all'array sottostante è molto pericoloso, devi sapere cosa stai facendo con ogni riga di codice e fare abbastanza test. I risultati del benchmark sono i seguenti:



WowUsare CollectionsMarshal è il 79% più veloce che usare foreach, ma dovrebbe essere il motivo dell'ottimizzazione per JIT, non c'è una grande differenza tra usare foreach e per il ciclo parola chiave Span.

sommario

Oggi vi ho parlato di come attraversare rapidamente la collezione List e, nella maggior parte dei casi, si consiglia di usare la parola chiave foreach, che prevede sia il controllo dell'overflow che il controllo multithread dei numeri di versione, il che può facilitare la scrittura del codice corretto.

Se hai bisogno di grandi prestazioni e volumi di dati grandi, è consigliato usare per CollectionsMarshal.AsSpan direttamente per attraversare la collezione.

Link al codice sorgente di questo articolo:

Il login del link ipertestuale è visibile.

Link originale:Il login del link ipertestuale è visibile.





Precedente:Spiegazione dettagliata dell'architettura dei messaggi AMQP di RabbitMQ
Prossimo:Testine a cristallo per cavi di rete T568A e T568B standard e differenze
Pubblicato il 4-9-2022 22:15:52 |
Impara a imparare
Pubblicato il 8-09-2022 alle 10:33:05 |
Impara a imparare
Pubblicato il 27-6-2023 22:39:13 |
Ciao 12306 Puoi mandarmi un messaggio privato con i dati
Disconoscimento:
Tutto il software, i materiali di programmazione o gli articoli pubblicati dalla Code Farmer Network sono destinati esclusivamente all'apprendimento e alla ricerca; I contenuti sopra elencati non devono essere utilizzati per scopi commerciali o illegali, altrimenti gli utenti dovranno sostenere tutte le conseguenze. Le informazioni su questo sito provengono da Internet, e le controversie sul copyright non hanno nulla a che fare con questo sito. Devi eliminare completamente i contenuti sopra elencati dal tuo computer entro 24 ore dal download. Se ti piace il programma, ti preghiamo di supportare software autentico, acquistare la registrazione e ottenere servizi autentici migliori. In caso di violazione, vi preghiamo di contattarci via email.

Mail To:help@itsvse.com