7
votes

Appeler une méthode dans une LINQ foreach - combien de frais généraux est là?

Je pense à remplacer beaucoup d'inine foreshees avec Linq et de faire de nouvelles méthodes, par ex. Courant: xxx

idée: xxx

méthode évidemment () contient le relevé1..3

est cette bonne pratique Ou appelle une méthode à des milliers de fois pour dégrader la performance? Mes listes ont 10 000 à 100 000 éléments.


1 commentaires

Personne ne sait quelle est votre tolérance pour la dégradation de la performance sauf vous. Écrivez le code des deux manières, mesurez les performances des façons, puis vous saurez.


4 Réponses :


12
votes

Eh bien, pour une chose que vous pouvez probablement rendre l'instruction foreach plus efficace à l'aide d'une conversion de groupe de méthode xxx

qui est supprimé un niveau d'indirection.

Personnellement, je ne pense pas que ce soit une bonne idée. La première approche est plus lisible et susceptible d'accomplir aussi. Quel est l'avantage d'utiliser la liste .foForeach ici?

Eric Lippert en parle d'autres dans un Excellent blog Publier . J'utiliserais list .foreach si vous déjà avait un délégué que vous vouliez exécuter contre chaque élément, mais je ne voudrais pas introduire un délégué et une méthode supplémentaire juste Pour le plaisir de cela.

en termes d'efficacité, je ne m'attendrais pas à voir beaucoup de différence. La première forme May fonctionne un peu mieux car elle n'a pas l'indirection de l'appel de délégué - mais la deuxième forme peut être plus efficace si la boucle d'itération dans Foreach utilise le fait qu'il a accès aux structures de données internes de la liste . Je doute très bien que vous le remarquerez de toute façon. Vous pouvez essayer de le mesurer si vous êtes vraiment dérangé, bien sûr.


6 commentaires

Peut-être que vous ignorez que quelqu'un une fois fait des comparaisons de performances assez étendues sur les différentes méthodes pour énumérer une liste . J'espère que cela pourra aider. :) MSMVPS.com/blogs/jon_skeet/archive/2006/ 01/20 / foreachperf.as px


@Ani: Gosh, j'avais complètement oublié ça. Vous venez de revenir sur le code avec .NET 4 et la version "Langue foreach" semble être quelque peu améliorée.


Qu'est-ce qu'une "conversion de groupe de méthodes" et comment ça vous aide?


@Ian: C'est la conversion du nom d'une méthode à un délégué. L'expression Lambda finira par créer une méthode supplémentaire simplement pour appeler la méthode . Les conversions de groupe de méthodes sont ce qui permet aux choses comme bouton.click + = clickhandler;


Re "Conversion de groupe de méthodes", merci, j'avais espéré que le compilateur C # optimiserait ceci c'est moi-même!


Mise à jour du lien vers @ Jonskeet's Foreach Performance Blogpost: codeblog.jonskeet.uk/2006/01/ 20 / foreachperf



2
votes

Si votre motivation pour envisager le changement est que les trois déclarations du corps sont trop compliquées, j'utiliserais probablement l'ordinaire foreach , mais refacteur le corps à une méthode: xxx

Si le code dans le corps n'est pas compliqué, je suis d'accord avec Jon qu'il n'y a pas de bonne raison pour utiliser foreach (il ne rend pas le code plus Lisible / déclaratif de quelque manière que ce soit).

i Généralement n'aime pas utiliser des constructions "Linq-like" pour effectuer un traitement impératif à la fin d'une requête LINQ. Je pense que l'utilisation de foreach indique plus clairement que vous avez terminé avec des données de requête et que vous faites du traitement maintenant.


0 commentaires

0
votes

J'ai toujours pensé que vous devriez d'abord écrire votre code pour que votre code soit lisible, car le compilateur et le CLR font un travail à l'optimisation. Si vous constatez que, grâce à une analyse comparative, ce code pourrait être exécuté plus rapidement, puis jetez un coup d'œil à d'autres options de tous les moyens.

E.g. Pour les boucles sont plus rapides que prévu, car ils utilisent des compensations de matrice optimisées en interne dans le CLR.

mais pas une liste.Foreseach () fait sûrement une pourcheche () de toute façon, de sorte que vous donnez simplement le travail à une autre méthode, plutôt que de le faire vous-même.

Strictement parlant, introduisant davantage d'appels de méthodes ralentira votre code sur la première passe, car le CLR sera compilé de méthodes tels qu'elles sont appelées, bien que les appels ultérieurs à la méthode ne seront pas.

Alors, mes conseils seraient debout pour écrire un code lisible, puis passer de là si vous pouvez prouver qu'il s'agit d'un goulot d'étranglement du système.


2 commentaires

Je ne sais pas où vous avez l'idée que le CLR est un travail aussi exceptionnel à l'optimisation. L'optimisation n'est pas facile, en particulier avec des éléments tels que le fil-threading et les effets secondaires (que c # inclut), et mon expérience indique que le CLR convient bien à l'élimination des frais généraux, mais que vous ne devriez pas vous attendre à ce qu'elle soit en mesure de réorganiser code pour même des variantes "équivalentes" de manière triviale plus rapide. Écrivez pour la lisibilité car la performance n'a pas d'importance, pas parce que vous attendez des miracles de l'optimiseur.


Je suppose que l'objectif est 2 pli: moins de code qui entraîne des avantages de performance. J'irais toujours être une lisibilité d'abord si cela refactore ou écrit plus de lignes de code pour aider à la maintenance. Mais prouver que c'est un goulot d'étranglement avant d'essayer d'optimiser.



1
votes

Je suis totalement d'accord avec la réponse de Jon Skeet. Mais puisque nous parlons de foreach code> performance, j'ai quelque chose d'aversion à votre question. Sachez que si votre déclaration 1 ~ 3 n'est pas relative les unes avec les autres, c'est-à-dire: xxx pré>

Le code ci-dessus a probablement une performance pire que ce qui suit: p>

foreach(Item in List) 
{ 
   DoSomething();
} 
foreach(Item in List) 
{ 
   DoAnotherThing(); 
} 
foreach(Item in List) 
{ 
   DoTheLastThing();
} 


1 commentaires

Je me demande combien d'articles dans cette liste Il faudrait avoir besoin d'obtenir les avantages des registres de la CPU chauds variables