Cet article est un article miroir de traduction automatique, veuillez cliquer ici pour accéder à l’article original.

Vue: 6317|Répondre: 3

[Source] [Tourne]. Optimisations des performances NET - parcourez rapidement les collections de listes

[Copié le lien]
Publié le 28-08-2022 à 20:51:16 | | | |
Brève introduction

System.Collections.Generic.List <T>est une classe de collection générique dans .NET, qui peut stocker tout type de données grâce à sa commodité et à son API riche, largement utilisée dans notre vie quotidienne, et peut être considérée comme la classe de collection la plus utilisée.

En écriture de code, il nous faut souvent itérer à travers une collection de listes <T>pour obtenir les éléments qu’elle contient pour un traitement métier. Normalement, il n’y a pas beaucoup d’éléments dans un décor et il est très rapide à traverser. Mais pour certains traitements de big data, statistiques, calcul en temps réel, etc<T>., comment parcourir rapidement la liste de collecte de dizaines de milliers ou de centaines de milliers de données ? C’est ce que je dois vous dire aujourd’hui.

Mode de déplacement

Examinons la performance des différentes méthodes de traversée, et construisons la référence de performance suivante, en utilisant différents ordres de grandeur de parcours de collections pour évaluer la performance de différentes méthodes. Le extrait de code ressemble à ceci :

Utilisez l’instruction foreach

Foreach est la méthode la plus courante pour parcourir les collections, c’est une implémentation syntax sugar du modèle itérateur, et elle sert également de référence pour cette période.

Parce que l’instruction foreach est un sucre syntaxique, le compilateur appelle finalement GetEnumerator() et MoveNext() avec une boucle while pour implémenter la fonctionnalité. Le code compilé ressemble à ceci :



L’implémentation de la méthode MoveNext() garantit qu’aucun autre thread ne modifie la collection dans l’itération, et si la modification a lieu, elle lance une exception InvalidOperationException, avec une vérification de débordement pour vérifier si l’index actuel est légitime, et elle doit également assigner l’élément correspondant à l’énumérateur. Attribut actuel,En fait, ses performances ne sont donc pas les meilleures, le extrait de code ressemble à ceci :



Voyons comment il se comporte sur différentes tailles de groupes, et les résultats ressemblent à ceci :



On peut constater que, dans le cas de tailles différentes, la relation de croissance linéaire du processus chronophage est nécessaire, même s’il parcourt 100w de données sans aucune logique de traitement, cela prend au moins 1 seconde.

Utilisez la méthode ForEach de la liste

Une autre méthode courante est d’utiliser List<T>. ForEach(), qui permet de passer un délégué d’action<T>, qui appellera le délégué d’action au fur et à mesure qu’il itère dans l’élément<T>.

C’est une <T>méthode d’implémentation interne de List, ce qui lui permet d’accéder directement aux tableaux privés et d’éviter les vérifications de débordement. En théorie, cela devrait être rapide ; Mais dans notre cas, il n’y a qu’une seule méthode vide, qui peut ne pas bien fonctionner avec un appel en ligne complet à la méthode foreach. Voici le code source de la méthode ForEach qui montre qu’elle ne dispose pas de vérification de débordement, mais qu’elle conserve tout de même la vérification simultanée des numéros de version.



De plus, puisqu’il est nécessaire de passer un délégué à la méthode ForEach dans le code d’appel, il vérifiera si l’objet délégué dans la classe de génération de clôture est vide à chaque fois, et sinon, un nouveau Action<T>(), comme montré ci-dessous :



Voyons comment il se compare au mot-clé foreach en termes de performance. L’image suivante montre les résultats du benchmark :



D’après les résultats du test, c’est 40 % plus lent que d’utiliser directement le mot-clé foreach ; il semble que si ce n’est pas nécessaire, il est préférable d’utiliser foreach directement, donc existe-t-il un moyen plus rapide ?

pour la traversée de boucles

Pour revenir à notre méthode la plus ancienne, qui consiste à utiliser le mot-clé for pour parcourir la collection. Cela devrait être la méthode de traversée la plus performante pour le moment, car elle ne nécessite pas de code redondant comme les précédentes (même si l’indexeur est aussi vérifié pour éviter les dépassements), et évidemment elle ne vérifie pas le numéro de version, donc dans un environnement multithread la collection est modifiée, et il n’y aura aucune exception lors de l’utilisation de for. Le code de test ressemble à ceci :

Voyons ce que ça donne.



Cela semble être ce à quoi nous nous attendons.Utiliser la boucle for directement est 60 % plus rapide que for, un ensemble qui prenait auparavant 1 seconde à parcourir, ne prend maintenant que 400 millisecondes. Alors, y a-t-il un moyen plus rapide ?

Utiliser CollectionsMarshal

Après .NET5, la communauté dotnet a implémenté la classe CollectionsMarshal afin d’améliorer les performances des opérations de collecte. Ce cours met en œuvre comment accéder à des tableaux natifs de types de collections (si vous avez vu mon [. .NET Performance Optimization - Vous devriez définir la taille initiale pour les types de collections], vous savez que l’implémentation sous-jacente de nombreuses structures de données est constituée de tableaux. Il peut donc passer toutes sortes de détections et accéder directement à l’array original, qui devrait être le plus rapide. Le code ressemble à ceci :

Vous pouvez voir que le code généré par le compilateur est très efficace.



L’accès direct au tableau sous-jacent est très dangereux, il faut savoir ce que l’on fait avec chaque ligne de code et avoir suffisamment de tests. Les résultats des benchmarks sont les suivants :



PleurageUtiliser CollectionsMarshal est 79 % plus rapide que l’utilisation de foreach, mais cela devrait être la raison de l’optimisation JIT, il n’y a pas de grande différence entre utiliser foreach et la boucle de mot-clé for Span.

résumé

Aujourd’hui, je vous ai parlé de la manière de parcourir rapidement la collection Liste, et dans la plupart des cas, il est recommandé d’utiliser le mot-clé foreach, qui propose à la fois une vérification de débordement et un contrôle multithread des numéros de version, ce qui peut faciliter l’écriture du bon code.

Si vous avez besoin de hautes performances et de volumes de données importants, il est recommandé d’utiliser directement CollectionsMarshal.AsSpan pour parcourir la collection.

Lien vers le code source de cet article :

La connexion hyperlientérée est visible.

Lien original :La connexion hyperlientérée est visible.





Précédent:Explication détaillée de l’architecture des messages AMQP de RabbitMQ
Prochain:Normes et différences entre la tête cristalline de câble réseau T568A et T568B
Publié le 04-09-2022 à 22:15:52 |
Apprendre à apprendre
Publié le 08-09-2022 à 10:33:05 |
Apprendre à apprendre
Publié le 27-06-2023 à 22:39:13 |
Bonjour 12306 Peux-tu m’envoyer un message privé avec les données
Démenti:
Tous les logiciels, supports de programmation ou articles publiés par Code Farmer Network sont uniquement destinés à l’apprentissage et à la recherche ; Le contenu ci-dessus ne doit pas être utilisé à des fins commerciales ou illégales, sinon les utilisateurs assumeront toutes les conséquences. Les informations sur ce site proviennent d’Internet, et les litiges de droits d’auteur n’ont rien à voir avec ce site. Vous devez supprimer complètement le contenu ci-dessus de votre ordinateur dans les 24 heures suivant le téléchargement. Si vous aimez le programme, merci de soutenir un logiciel authentique, d’acheter l’immatriculation et d’obtenir de meilleurs services authentiques. En cas d’infraction, veuillez nous contacter par e-mail.

Mail To:help@itsvse.com