Sont liste-des compréhensions et fonctionnelle des fonctions plus rapide que “pour les boucles”?
En termes de performances en Python, une liste-de la compréhension, ou des fonctions telles que map(), filter() et reduce() plus rapide qu'une boucle for? Pourquoi, techniquement, ils ont "exécuter dans un C vitesse", tandis que "la boucle for s'exécute dans le python de la machine virtuelle de vitesse"?.
Supposons que, dans un jeu que je suis en développement, j'ai besoin de tirer complexe et énorme de cartes à l'aide de boucles. Cette question serait certainement pertinent, car si une liste-de la compréhension, par exemple, est en effet plus rapide, ce serait une bien meilleure option pour éviter les lag (Malgré le visuel de la complexité du code).
InformationsquelleAutor Ericson Willians | 2014-03-01
Vous devez vous connecter pour publier un commentaire.
Les éléments suivants sont des lignes directrices et des suppositions éclairées, fondées sur l'expérience. Vous devriez
timeit
ou le profil de votre cas concret d'utilisation pour obtenir des chiffres précis, et ces chiffres peuvent parfois être en désaccord avec le ci-dessous.Une compréhension de liste est généralement un tout petit peu plus rapide que précisément l'équivalent
for
boucle (qui en fait construit une liste), probablement parce qu'elle n'a pas de consulter la liste et saappend
méthode à chaque itération. Cependant, une compréhension de liste ne fonctionne toujours un bytecode niveau de la boucle:À l'aide d'une compréhension de liste à la place d'une boucle qui n'est pas construire une liste, inepte à accumuler une liste de sens des valeurs, puis de le jeter à la liste, est souvent plus lent en raison de la charge de la création et de l'extension de la liste. Interprétations de la liste ne sont pas de la magie qui est intrinsèquement plus rapide qu'un bon vieux boucle.
Comme pour la fonctionnelle de la liste de fonctions de traitement: Alors que ceux-ci sont écrits en C et probablement surpasser l'équivalent de fonctions écrites en Python, ils sont pas nécessairement l'option la plus rapide. La vitesse devrait si la fonction est écrite en C trop. Mais la plupart des cas à l'aide d'un
lambda
(ou autre fonction Python), les frais généraux, à plusieurs reprises, la configuration de Python pile de cadres etc. mange de toutes les économies. Simplement faire le même travail en ligne, sans appels de fonction (par exemple, une compréhension de liste au lieu demap
oufilter
) est souvent légèrement plus rapide.Les Chances sont, si ce type de code n'est pas déjà assez rapide lorsqu'il est écrit en bon non"optimisé" de Python, aucun montant de Python niveau de la micro-optimisation va le faire assez rapidement et vous devriez commencer à penser à tomber à C. de vastes micro-optimisations peuvent souvent accélérer code Python considérablement, il est faible (en valeur absolue) de limiter à cela. Par ailleurs, même avant que vous frappez ce plafond, il devient tout simplement plus rentable (15% de l'accélération de vs 300% de la vitesse avec le même effort) mordre la balle et écrire quelques C.
Si vous cochez la info sur python.org, vous pouvez voir ce résumé:
Mais vous avez vraiment devrait lire l'article ci-dessus dans les détails pour comprendre la cause de la différence de performances.
Je suggérons fortement que vous devriez de temps votre code à l'aide de timeit. À la fin de la journée, il peut y avoir une situation où, par exemple, vous pouvez avoir besoin de sortir de
for
boucle lorsqu'une condition est remplie. Il pourrait être plus rapide que de trouver le résultat en appelantmap
.Vous demandez spécifiquement sur la map(), filter() et reduce(), mais je suppose que vous voulez savoir sur la programmation fonctionnelle en général. Pour l'avoir testé moi-même sur le problème de calcul des distances entre tous les points à l'intérieur d'un ensemble de points, la programmation fonctionnelle (à l'aide de la starmap fonction de l'intégré dans le module itertools) s'est avéré pour être un peu plus lent que pour les boucles (prise de 1,25 fois plus long, en fait). Voici un exemple de code que j'ai utilisé:
Est la version fonctionnelle plus rapide que la version procédurale?
J'ai écrit un script simple test de la vitesse et c'est ce que j'ai trouvé. En fait pour la boucle a été le plus rapide dans mon cas. Que vraiment surpris moi, découvrez le soufflet (était en train de calculer la somme des carrés).
0:00:00.302000 #Reduce
0:00:00.144000 #For loop
0:00:00.318000 #Map
0:00:00.390000 #List comprehension
int
danssquare_sum4
rend aussi un peu plus rapide et juste un peu plus lent que pour la boucle.Ajoutant une touche de Alphii répondre, en fait, la boucle serait le deuxième meilleur et environ 6 fois plus lent que
map
Principaux changements ont été d'éliminer les lentes
sum
appels, ainsi que le probablement inutileint()
dans le dernier cas. Mettre la boucle for et la carte dans les mêmes termes, bien fait, en fait. Rappelez-vous que les lambdas sont les concepts de fonctions et, théoriquement, ne devrait pas avoir d'effets secondaires, mais, bon, ils peut avoir des effets secondaires comme l'ajout dea
.Les résultats dans ce cas avec Python 3.6.1, Ubuntu 14.04, Intel(R) Core(TM) i7-4770 CPU @ 3.40 GHz
J'ai réussi à modifier certains de @alpiii de l' code et découvert que la compréhension de Liste est un peu plus rapide que pour la boucle. Elle peut être provoquée par l'
int()
, il n'est pas juste entre la liste de la compréhension et de la boucle.0:00:00.101122
0:00:00.089216
0:00:00.101532
0:00:00.068916