En C # / VB.NET / .NET, quelle boucle s'exécute plus rapidement, for
ou foreach
?
Depuis que j'ai lu qu'une for
boucle fonctionne plus rapidement qu'une foreach
boucle il y a longtemps, j'ai supposé qu'elle était vraie pour toutes les collections, les collections génériques, tous les tableaux, etc.
J'ai parcouru Google et trouvé quelques articles, mais la plupart d'entre eux ne sont pas concluants (lire les commentaires sur les articles) et ouverts.
L'idéal serait de répertorier chaque scénario et la meilleure solution pour le même.
Par exemple (juste un exemple de comment cela devrait être):
- pour itérer un tableau de plus de 1000 chaînes -
for
est mieux queforeach
- pour itérer sur
IList
des chaînes (non génériques) -foreach
est mieux quefor
Quelques références trouvées sur le web pour les mêmes:
- Grand ancien article original d'Emmanuel Schanzer
- CodeProject FOREACH Vs. POUR
- Blog - To
foreach
to not toforeach
, telle est la question - Forum ASP.NET - NET 1.1 C #
for
vsforeach
[Éditer]
Hormis l'aspect lisibilité de celui-ci, je suis vraiment intéressé par les faits et les chiffres. Il existe des applications où le dernier kilomètre d'optimisation des performances est important.
la source
foreach
au lieu defor
C #. Si vous voyez ici des réponses qui n'ont aucun sens, c'est pourquoi. Blâmez le modérateur, pas les réponses malheureuses.Réponses:
Patrick Smacchia a blogué à ce sujet le mois dernier, avec les conclusions suivantes:
la source
foreach
que pour parcourir un tableau avecfor
, et vous appelez cela insignifiant? Ce genre de différence de performances peut être important pour votre application, et ce n'est peut-être pas le cas, mais je ne voudrais pas simplement le rejeter d'emblée.foreach
s.Tout d'abord, une demande reconventionnelle à la réponse de Dmitry (maintenant supprimée) . Pour les tableaux, le compilateur C # émet en grande partie le même code
foreach
que pour unefor
boucle équivalente . Cela explique pourquoi pour ce benchmark, les résultats sont fondamentalement les mêmes:Résultats:
Ensuite, vérifiez que le point de Greg sur le type de collection est important - changez le tableau en a
List<double>
dans ce qui précède, et vous obtenez des résultats radicalement différents. Non seulement il est considérablement plus lent en général, mais foreach devient beaucoup plus lent que l'accès par index. Cela dit, je préférerais presque toujours foreach à une boucle for où cela rend le code plus simple - car la lisibilité est presque toujours importante, alors que la micro-optimisation l'est rarement.la source
List<T>
? La lisibilité l'emporte-t-elle également sur la micro-optimisation?List<T>
tableaux. Les exceptions sontchar[]
etbyte[]
qui sont plus souvent traitées comme des «morceaux» de données plutôt que comme des collections normales.foreach
les boucles démontrent une intention plus spécifique que lesfor
boucles .L'utilisation d'une
foreach
boucle montre à toute personne utilisant votre code que vous prévoyez de faire quelque chose à chaque membre d'une collection, quelle que soit sa place dans la collection. Il montre également que vous ne modifiez pas la collection d'origine (et lève une exception si vous essayez de le faire).L'autre avantage de cela
foreach
est qu'il fonctionne sur n'importe quelIEnumerable
, où celafor
n'a de sens que pourIList
, où chaque élément a en fait un index.Cependant, si vous devez utiliser l'index d'un élément, vous devez bien sûr être autorisé à utiliser une
for
boucle. Mais si vous n'avez pas besoin d'utiliser un index, en avoir un ne fait qu'encombrer votre code.Pour autant que je sache, il n'y a aucune incidence significative sur les performances. À un certain moment dans le futur, il pourrait être plus facile d'adapter le code à l'aide
foreach
de plusieurs cœurs, mais ce n'est pas quelque chose à craindre pour le moment.la source
foreach
.foreach
n'est pas du tout lié à la programmation fonctionnelle. C'est totalement un paradigme impératif de la programmation. Vous attribuez à tort des choses qui se produisent dans TPL et PLINQforeach
.foreach
équivalent d'unewhile
boucle). Je pense que je sais que @ctford fait référence. La bibliothèque parallèle de tâches permet à la collection sous-jacente de fournir des éléments dans un ordre arbitraire (en faisant appel.AsParallel
à un énumérable).foreach
ne fait rien ici et le corps de la boucle est exécuté sur un seul thread . La seule chose qui est parallélisée est la génération de la séquence.foreach
et lesfor
performances pour les listes normales est de quelques fractions de seconde pour itérer sur des millions d'éléments, de sorte que votre problème n'était certainement pas directement lié aux performances foreach, du moins pas pour quelques centaines d'objets. Cela ressemble à une implémentation d'énumérateur cassée dans la liste que vous utilisiez.Chaque fois qu'il y a des arguments sur les performances, il vous suffit d'écrire un petit test afin que vous puissiez utiliser des résultats quantitatifs pour soutenir votre cas.
Utilisez la classe StopWatch et répétez quelque chose plusieurs millions de fois, pour plus de précision. (Cela pourrait être difficile sans une boucle for):
Les doigts ont croisé les résultats de cette démonstration que la différence est négligeable, et vous pourriez tout aussi bien faire tout ce qui se traduit par le code le plus maintenable
la source
Ce sera toujours proche. Pour un tableau, c'est parfois un
for
peu plus rapide, mais ilforeach
est plus expressif et offre LINQ, etc. En général, respectezforeach
.En outre,
foreach
peut être optimisé dans certains scénarios. Par exemple, une liste chaînée peut être terrible par indexeur, mais elle peut être rapide parforeach
. En fait, la normeLinkedList<T>
n'offre même pas d'indexeur pour cette raison.la source
LinkedList<T>
c'est plus maigre queList<T>
? Et si je vais toujours utiliserforeach
(au lieu defor
), je ferais mieux d'utiliserLinkedList<T>
?List<T>
). C'est plus qu'il est moins cher à insérer / retirer .Je suppose que ce ne sera probablement pas significatif dans 99% des cas, alors pourquoi choisiriez-vous le plus rapide au lieu du plus approprié (comme dans le plus facile à comprendre / à maintenir)?
la source
Il est peu probable qu'il y ait une énorme différence de performances entre les deux. Comme toujours, face à un "qui est plus rapide?" question, vous devez toujours penser "je peux mesurer cela."
Écrivez deux boucles qui font la même chose dans le corps de la boucle, exécutez-les et chronométrez-les toutes les deux, et voyez quelle est la différence de vitesse. Faites-le avec un corps presque vide et un corps de boucle similaire à ce que vous allez réellement faire. Essayez-le également avec le type de collection que vous utilisez, car différents types de collections peuvent avoir des caractéristiques de performances différentes.
la source
Il y a de très bonnes raisons de préférer les
foreach
boucles auxfor
boucles. Si vous pouvez utiliser uneforeach
boucle, votre patron a raison.Cependant, chaque itération ne passe pas simplement par une liste dans l'ordre un par un. S'il interdit , oui, c'est faux.
Si j'étais vous, ce que je ferais, c'est transformer toutes vos boucles naturelles en récursivité . Cela lui apprendrait, et c'est aussi un bon exercice mental pour vous.
la source
for
boucles et aux boucles enforeach
termes de performances?Jeffrey Richter sur TechEd 2005:
Webdiffusion à la demande: http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032292286&EventCategory=3&culture=en-US&CountryCode=US
la source
C'est ridicule. Il n'y a aucune raison impérieuse d'interdire la boucle for, en termes de performances ou autre.
Voir le blog de Jon Skeet pour une référence de performance et d'autres arguments.
la source
Dans les cas où vous travaillez avec une collection d'objets,
foreach
c'est mieux, mais si vous incrémentez un nombre, unefor
boucle est meilleure.Notez que dans le dernier cas, vous pourriez faire quelque chose comme:
Mais il ne fonctionne certainement pas mieux, il a en fait des performances inférieures à celles d'un
for
.la source
Cela devrait vous faire économiser:
Utilisation:
Pour une plus grande victoire, vous pouvez prendre trois délégués comme paramètres.
la source
for
boucle est généralement écrite pour exclure la fin de la plage (par exemple0 <= i < 10
).Parallel.For
fait également cela pour le garder facilement interchangeable avec unefor
boucle commune .vous pouvez en lire plus dans Deep .NET - partie 1 Itération
il couvre les résultats (sans la première initialisation) du code source .NET jusqu'au démontage.
par exemple - Array Iteration avec une boucle foreach:
et - lister l'itération avec la boucle foreach:
et les résultats finaux:
la source
Les différences de vitesse dans une boucle
for
- et uneforeach
- sont minuscules lorsque vous parcourez des structures courantes comme des tableaux, des listes, etc., et faire uneLINQ
requête sur la collection est presque toujours un peu plus lent, bien que ce soit plus agréable à écrire! Comme les autres affiches l'ont dit, optez pour l'expressivité plutôt qu'une milliseconde de performances supplémentaires.Ce qui n'a pas été dit jusqu'à présent, c'est que lorsqu'une
foreach
boucle est compilée, elle est optimisée par le compilateur en fonction de la collection sur laquelle elle itère. Cela signifie que lorsque vous n'êtes pas sûr de la boucle à utiliser, vous devez utiliser laforeach
boucle - elle générera la meilleure boucle pour vous lorsqu'elle sera compilée. C'est aussi plus lisible.Un autre avantage clé de la
foreach
boucle est que si votre implémentation de collection change (d'un intarray
à unList<int>
par exemple), votreforeach
boucle ne nécessitera aucune modification de code:Ce qui précède est le même quel que soit le type de votre collection, alors que dans votre
for
boucle, ce qui suit ne sera pas construit si vous êtes passémyCollection
de anarray
à aList
:la source
"Y a-t-il des arguments que je pourrais utiliser pour m'aider à le convaincre que la boucle for est acceptable?"
Non, si votre patron fait de la microgestion au point de vous dire quels concepts de langage de programmation utiliser, il n'y a vraiment rien à dire. Désolé.
la source
Cela dépend probablement du type de collection que vous énumérez et de l'implémentation de son indexeur. En général cependant, l'utilisation
foreach
est probablement une meilleure approche.En outre, cela fonctionnera avec tout
IEnumerable
- pas seulement avec les indexeurs.la source
Cela a les deux mêmes réponses que la plupart des questions "ce qui est plus rapide":
1) Si vous ne mesurez pas, vous ne savez pas.
2) (Parce que ...) Cela dépend.
Cela dépend du coût de la méthode "MoveNext ()", par rapport au coût de la méthode "this [int index]", pour le type (ou les types) de IEnumerable que vous allez parcourir.
Le mot clé "foreach" est un raccourci pour une série d'opérations - il appelle GetEnumerator () une fois sur l'IEnumerable, il appelle MoveNext () une fois par itération, il effectue une vérification de type, etc. La chose la plus susceptible d'avoir un impact sur les mesures de performances est le coût de MoveNext () car il est invoqué O (N) fois. C'est peut-être bon marché, mais peut-être pas.
Le mot clé "for" semble plus prévisible, mais dans la plupart des boucles "for", vous trouverez quelque chose comme "collection [index]". Cela ressemble à une opération d'indexation de tableau simple, mais il s'agit en fait d'un appel de méthode, dont le coût dépend entièrement de la nature de la collection sur laquelle vous effectuez l'itération. C'est probablement bon marché, mais ce n'est peut-être pas le cas.
Si la structure sous-jacente de la collection est essentiellement une liste chaînée, MoveNext est bon marché, mais l'indexeur peut avoir un coût O (N), ce qui rend le coût réel d'une boucle "pour" O (N * N).
la source
Chaque construction de langage a une heure et un lieu appropriés pour son utilisation. Il y a une raison pour laquelle le langage C # a quatre instructions d'itération distinctes - chacune est là pour un objectif spécifique et a une utilisation appropriée.
Je recommande de vous asseoir avec votre patron et d'essayer d'expliquer rationnellement pourquoi une
for
boucle a un but. Parfois, unfor
bloc d'itération décrit plus clairement un algorithme qu'uneforeach
itération. Lorsque cela est vrai, il convient de les utiliser.Je voudrais également signaler à votre patron - La performance n'est pas, et ne devrait pas être un problème de quelque manière pratique - c'est plus une question d'expression de l'algorithme d'une manière succincte, significative et maintenable. Les micro-optimisations comme celle-ci manquent complètement l'optimisation des performances, car tout avantage réel en termes de performances proviendra d'une refonte et d'une refactorisation algorithmiques, et non d'une restructuration de boucle.
Si, après une discussion rationnelle, il y a toujours ce point de vue autoritaire, c'est à vous de décider comment procéder. Personnellement, je ne serais pas heureux de travailler dans un environnement où la pensée rationnelle est découragée et envisagerais de passer à un autre poste sous un autre employeur. Cependant, je recommande fortement la discussion avant de s'énerver - il peut simplement y avoir un simple malentendu.
la source
C'est ce que vous faites à l' intérieur de la boucle qui affecte les performances, pas la construction de boucle réelle (en supposant que votre cas n'est pas trivial).
la source
Que ce
for
soit plus rapide que ce quiforeach
est vraiment hors de propos. Je doute fortement que choisir l'un plutôt que l'autre ait un impact significatif sur vos performances.La meilleure façon d'optimiser votre application consiste à profiler le code réel. Cela identifiera les méthodes qui représentent le plus de travail / temps. Optimisez-les d'abord. Si les performances ne sont toujours pas acceptables, répétez la procédure.
En règle générale, je recommanderais de rester à l'écart des micro-optimisations car elles donneront rarement des gains significatifs. La seule exception est lors de l'optimisation des chemins d'accès identifiés (c.-à-d. Si votre profilage identifie quelques méthodes très utilisées, il peut être judicieux de les optimiser largement).
la source
for
est légèrement plus rapide queforeach
. Je m'opposerais sérieusement à cette déclaration. Cela dépend totalement de la collection sous-jacente. Si une classe de liste liée fournit un indexeur avec un paramètre entier, je m'attendrais à ce qu'unefor
boucle soit O (n ^ 2) alors qu'elleforeach
devrait être O (n).for
et la recherche d'un indexeur à l'utilisationforeach
seule. Je pense que la réponse de @Brian Rasmussen est correcte, à part toute utilisation avec une collection,for
sera toujours légèrement plus rapide queforeach
. Cependant,for
plus une recherche de collection sera toujours plus lente queforeach
par elle-même.for
instruction. Lafor
boucle simple avec une variable de contrôle entière n'est pas comparable àforeach
, donc c'est fini. Je comprends ce que @Brian signifie et c'est correct comme vous le dites, mais la réponse peut être trompeuse. Re: Votre dernier point: non, en fait,for
plusList<T>
est encore plus rapide queforeach
.Les deux fonctionneront presque exactement de la même manière. Écrivez du code pour utiliser les deux, puis montrez-lui l'IL. Il doit montrer des calculs comparables, ce qui signifie aucune différence de performances.
la source
for a une logique plus simple à implémenter, donc c'est plus rapide que foreach.
la source
À moins que vous ne soyez dans un processus d'optimisation de vitesse spécifique, je dirais utiliser la méthode qui produit le code le plus facile à lire et à maintenir.
Si un itérateur est déjà configuré, comme avec l'une des classes de collection, alors foreach est une bonne option facile. Et si c'est une plage entière que vous itérez, alors c'est probablement plus propre.
la source
Jeffrey Richter a parlé de la différence de performances entre for et foreach sur un podcast récent: http://pixel8.infragistics.com/shows/everything.aspx#Episode:9317
la source
Dans la plupart des cas, il n'y a vraiment aucune différence.
En règle générale, vous devez toujours utiliser foreach lorsque vous n'avez pas d'index numérique explicite, et vous devez toujours utiliser for lorsque vous n'avez pas réellement de collection itérable (par exemple, itérer sur une grille de tableau à deux dimensions dans un triangle supérieur) . Dans certains cas, vous avez le choix.
On pourrait faire valoir que pour les boucles peut être un peu plus difficile à maintenir si des nombres magiques commencent à apparaître dans le code. Vous devriez avoir raison d'être ennuyé de ne pas pouvoir utiliser une boucle for et d'avoir à créer une collection ou à utiliser un lambda pour construire une sous-collection à la place simplement parce que les boucles for ont été interdites.
la source
Il semble un peu étrange d'interdire totalement l'utilisation de quelque chose comme une boucle for.
Il y a un article intéressant ici qui couvre beaucoup de différences de performances entre les deux boucles.
Je dirais personnellement que je trouve foreach un peu plus lisible pour les boucles, mais vous devriez utiliser le meilleur pour le travail à effectuer et ne pas avoir à écrire du code extra long pour inclure une boucle foreach si une boucle for est plus appropriée.
la source
J'ai trouvé la
foreach
boucle qui itèreList
plus rapidement . Voir mes résultats de test ci-dessous. Dans le code ci-dessous, j'itère unearray
taille 100, 10000 et 100000 séparément en utilisantfor
et enforeach
boucle pour mesurer le temps.MISE À JOUR
Après la suggestion de @jgauffin, j'ai utilisé le code @johnskeet et constaté que la
for
boucle avecarray
est plus rapide que la suivante,Voir mes résultats de test et mon code ci-dessous,
la source
Vous pouvez vraiment visser avec sa tête et opter pour une fermeture IQueryable .foreach à la place:
la source
myList.ForEach(Console.WriteLine)
.Je ne m'attendrais pas à ce que quelqu'un trouve une "énorme" différence de performances entre les deux.
Je suppose que la réponse dépend du fait que la collection à laquelle vous essayez d'accéder ait une implémentation d'accès indexeur plus rapide ou une implémentation d'accès IEnumerator plus rapide. Étant donné que IEnumerator utilise souvent l'indexeur et ne contient qu'une copie de la position d'index actuelle, je m'attends à ce que l'accès de l'énumérateur soit au moins aussi lent ou plus lent que l'accès direct à l'index, mais pas de beaucoup.
Bien sûr, cette réponse ne tient pas compte des optimisations que le compilateur peut implémenter.
la source
Gardez à l'esprit que la boucle for et la boucle foreach ne sont pas toujours équivalentes. Les énumérateurs de liste lèveront une exception si la liste change, mais vous n'obtiendrez pas toujours cet avertissement avec une boucle for normale. Vous pourriez même obtenir une exception différente si la liste change au mauvais moment.
la source