Tout d'abord, je comprends que dans 90% des applications, la différence de performance est complètement hors de propos, mais j'ai juste besoin de savoir quelle est la construction la plus rapide. Cela et ...
Les informations actuellement disponibles à leur sujet sur le net prêtent à confusion. Beaucoup de gens disent que foreach est mauvais, mais techniquement, il devrait être plus rapide car il est supposé simplifier l'écriture d'un parcours de tableau à l'aide d'itérateurs. Les itérateurs, qui sont à nouveau supposés être plus rapides, mais en PHP sont aussi apparemment très lents (ou n'est-ce pas une chose PHP?). Je parle des fonctions de tableau: next () prev () reset () etc. eh bien, si ce sont même des fonctions et non une de ces fonctionnalités du langage PHP qui ressemblent à des fonctions.
Pour affiner un peu ceci : je ne suis pas intéressé à parcourir des tableaux par pas de plus de 1 (pas d'étapes négatives non plus, c'est-à-dire. Itération inverse). Je ne suis pas non plus intéressé par un parcours vers et depuis des points arbitraires, juste 0 à la longueur. Je ne vois pas non plus la manipulation de tableaux avec plus de 1000 clés sur une base régulière, mais je vois un tableau traversé plusieurs fois dans la logique d'une application! Aussi pour les opérations, en grande partie uniquement la manipulation et l'écho de chaînes.
Voici quelques sites de référence:
http://www.phpbench.com/
http://www.php.lt/benchmark/phpbench.php
Ce que j'entends partout:
foreach
est lent, et doncfor
/while
est plus rapide- PHPs
foreach
copie le tableau sur lequel il itère; pour accélérer les choses, vous devez utiliser des références - code comme celui-ci:
$key = array_keys($aHash); $size = sizeOf($key);
est plus rapide qu'un
for ($i=0; $i < $size; $i++)foreach
Voici mon problème. J'ai écrit ce script de test: http://pastebin.com/1ZgK07US et quel que soit le nombre de fois que je lance le script, j'obtiens quelque chose comme ceci:
foreach 1.1438131332397
foreach (using reference) 1.2919359207153
for 1.4262869358063
foreach (hash table) 1.5696921348572
for (hash table) 2.4778981208801
En bref:
foreach
est plus rapide queforeach
qu'avec référenceforeach
est plus rapide quefor
foreach
est plus rapide quefor
pour une table de hachage
Quelqu'un peut-il expliquer?
- Est-ce que je fais quelque chose de mal?
- PHP foreach fait-il vraiment une différence? Je veux dire pourquoi ne le copierait-il pas si vous passez par référence?
- Quel est le code d'itérateur équivalent pour l'instruction foreach; J'en ai vu quelques-uns sur le net, mais à chaque fois que je les teste, le timing est très éloigné; J'ai également testé quelques constructions d'itérateurs simples, mais je ne semble jamais obtenir de résultats même décents - les itérateurs de tableau en PHP sont-ils simplement horribles?
- Existe-t-il des moyens / méthodes / constructions plus rapides pour parcourir un tableau autre que FOR / FOREACH (et WHILE)?
PHP version 5.3.0
Edit: Answer Avec l'aide de personnes ici, j'ai pu rassembler les réponses à toutes les questions. Je vais les résumer ici:
- "Est-ce que je fais quelque chose de mal?"Le consensus semble être: oui, je ne peux pas utiliser l'écho dans les benchmarks. Personnellement, je ne vois toujours pas en quoi l'écho est une fonction avec un temps d'exécution aléatoire ou en quoi une autre fonction est en quelque sorte différente - cela et la capacité de ce script à générer exactement les mêmes résultats de foreach mieux que tout est difficile pour expliquer si juste "vous utilisez echo" (enfin ce que j'aurais dû utiliser). Cependant, je reconnais que le test devrait être fait avec quelque chose de mieux; bien qu'un compromis idéal ne me vienne pas à l'esprit.
- "Est-ce que PHP pour chaque référence fait vraiment une différence? Je veux dire pourquoi ne le copierait-il pas si vous passez par référence?" ircmaxell montre que oui, des tests supplémentaires semblent prouver dans la plupart des cas que la référence devrait être plus rapide - bien que compte tenu de mon extrait de code ci-dessus, cela ne signifie certainement pas tout. J'accepte que le problème soit probablement trop peu intuitif pour être dérangé à un tel niveau et qu'il faudrait quelque chose d'extrême comme la décompilation pour déterminer ce qui est le mieux pour chaque situation.
- "Quel est le code d'itérateur équivalent pour l'instruction foreach? J'en ai vu quelques-uns sur le net mais à chaque fois que je les teste, le timing est très éloigné. J'ai également testé quelques constructions d'itérateur simples mais je ne semble jamais obtenir de résultats même décents - les itérateurs de tableaux en PHP sont-ils vraiment horribles? " ircmaxell a fourni la réponse ci-dessous; bien que le code ne soit valide que pour la version PHP> = 5
- "Existe-t-il des moyens / méthodes / constructions plus rapides pour parcourir un tableau autre que FOR / FOREACH (et WHILE)?" Merci à Gordon pour la réponse. L'utilisation de nouveaux types de données dans PHP5 devrait améliorer les performances ou la mémoire (ce qui peut être souhaitable selon votre situation). Bien que beaucoup de nouveaux types de tableaux ne semblent pas être meilleurs que array () en termes de vitesse, splpriorityqueue et splobjectstorage semblent être nettement plus rapides. Lien fourni par Gordon: http://matthewturland.com/2010/05/20/new-spl-features-in-php-5-3/
Merci à tous ceux qui ont essayé d'aider.
Je vais probablement m'en tenir à foreach (la version sans référence) pour toute traversée simple.
Réponses:
Mon opinion personnelle est d'utiliser ce qui a du sens dans le contexte. Personnellement, je n'utilise presque jamais
for
pour la traversée de tableaux. Je l'utilise pour d'autres types d'itérations, maisforeach
c'est trop simple ... Le décalage horaire sera minime dans la plupart des cas.La grande chose à surveiller est:
C'est une boucle coûteuse, car elle appelle compter à chaque itération. Tant que vous ne faites pas cela, je ne pense pas que cela compte vraiment ...
En ce qui concerne la référence faisant la différence, PHP utilise la copie sur écriture, donc si vous n'écrivez pas dans le tableau, il y aura relativement peu de temps système lors de la boucle. Cependant, si vous commencez à modifier le tableau dans le tableau, c'est là que vous commencerez à voir les différences entre eux (car il faudra copier le tableau entier, et la référence peut simplement modifier en ligne) ...
Quant aux itérateurs,
foreach
équivaut à:Dans la mesure où il existe des moyens plus rapides d'itérer, cela dépend vraiment du problème. Mais j'ai vraiment besoin de demander pourquoi? Je comprends vouloir rendre les choses plus efficaces, mais je pense que vous perdez votre temps pour une micro-optimisation. Souvenez-vous,
Premature Optimization Is The Root Of All Evil
...Edit: Sur la base du commentaire, j'ai décidé de faire une course de référence rapide ...
Et les résultats:
Donc, si vous modifiez le tableau dans la boucle, il est plusieurs fois plus rapide d'utiliser des références ...
Et la surcharge pour la seule référence est en fait inférieure à la copie du tableau (c'est sur 5.3.2) ... Il apparaît donc (au moins sur 5.3.2) comme si les références étaient beaucoup plus rapides ...
la source
"the better standard way to adopt."
performance @srcspider n'est pas le seul critère pour choisir ce qu'il faut adopter. surtout dans un cas aussi tiré par les cheveux. Franchement, vous perdez votre tempsJe ne suis pas sûr que ce soit si surprenant. La plupart des gens qui codent en PHP ne sont pas bien familiarisés avec ce que fait PHP dans le bare metal. Je vais dire quelques choses, ce qui sera vrai la plupart du temps:
Si vous ne modifiez pas la variable, la valeur par valeur est plus rapide en PHP. C'est parce que sa référence est comptée de toute façon et que la valeur lui donne moins à faire. Il sait à la seconde où vous modifiez ce ZVAL (la structure de données interne de PHP pour la plupart des types), il devra le rompre de manière directe (copiez-le et oubliez l'autre ZVAL). Mais vous ne le modifiez jamais, donc cela n'a pas d'importance. Les références rendent cela plus compliqué avec plus de comptabilité qu'il faut faire pour savoir quoi faire lorsque vous modifiez la variable. Donc, si vous êtes en lecture seule, paradoxalement, il vaut mieux ne pas le remarquer avec le &. Je sais, c'est contre-intuitif, mais c'est aussi vrai.
Foreach n'est pas lent. Et pour une itération simple, la condition contre laquelle il teste - "suis-je à la fin de ce tableau" - est faite en utilisant du code natif, pas des opcodes PHP. Même s'il s'agit d'opcodes mis en cache par APC, c'est toujours plus lent qu'un tas d'opérations natives effectuées sur le bare metal.
L'utilisation d'une boucle for "for ($ i = 0; $ i <count ($ x); $ i ++) est lente à cause du count () et du manque de capacité de PHP (ou vraiment de tout langage interprété) à évaluer lors de l'analyse time si quelque chose modifie le tableau. Cela l'empêche d'évaluer le nombre une fois.
Mais même une fois que vous le corrigez avec "$ c = count ($ x); for ($ i = 0; $ i <$ c; $ i ++) le $ i <$ c est au mieux un tas d'opcodes Zend, tel quel le $ i ++. Au cours de 100 000 itérations, cela peut avoir de l'importance. Foreach sait au niveau natif ce qu'il faut faire. Aucun opcode PHP nécessaire pour tester la condition "suis-je à la fin de ce tableau".
Qu'en est-il de la vieille école "while (list (" stuff? Eh bien, utiliser each (), current (), etc. impliquera tous au moins un appel de fonction, ce qui n'est pas lent, mais pas gratuit. Oui, ceux-ci sont à nouveau des opcodes PHP! Donc, tandis que + list + chacun a ses coûts aussi.
Pour ces raisons, chacun est naturellement la meilleure option pour une itération simple.
Et n'oubliez pas, c'est aussi le plus facile à lire, donc c'est gagnant-gagnant.
la source
Une chose à surveiller dans les benchmarks (en particulier phpbench.com), c'est que même si les chiffres sont solides, les tests ne le sont pas. Beaucoup de tests sur phpbench.com sont triviaux et abusent de la capacité de PHP à mettre en cache les recherches de tableaux pour fausser les benchmarks ou dans le cas d'une itération sur un tableau ne le testent pas réellement dans des cas réels (personne n'écrit vide pour boucles). J'ai fait mes propres tests de performance qui reflètent assez bien les résultats du monde réel et ils montrent toujours la syntaxe itérative native du langage
foreach
en tête (surprise, surprise).la source
Nous sommes en 2020 et les choses ont beaucoup évolué avec php 7.4 et opcache .
Voici le benchmark OP ^, exécuté en tant que CLI unix , sans les parties echo et html.
Le test a été exécuté localement sur un ordinateur standard.
Script de référence modifié:
Production:
Comme vous pouvez le voir, l'évolution est folle, environ 560 fois plus rapide que celle rapportée en 2012.
Sur mes machines et serveurs, suite à mes nombreuses expériences, les bases des boucles sont les plus rapides. C'est encore plus clair en utilisant des boucles imbriquées ( $ i $ j $ k ..)
C'est aussi le plus flexible dans l'utilisation, et a une meilleure lisibilité de mon point de vue.
la source
Je pense mais je ne suis pas sûr: la
for
boucle prend deux opérations pour vérifier et incrémenter les valeurs.foreach
charge les données en mémoire puis itère toutes les valeurs.la source