Accélérer Python

il s'agit en fait de deux questions, mais elles sont tellement similaires, et pour rester simple, j'ai pensé que je voudrais juste les rouler ensemble:

  • tout d'abord : étant donné un projet python établi, quels sont les moyens décents pour l'accélérer au-delà d'une simple optimisation en code?

  • Deuxièmement : quand on écrit un programme à partir de zéro en python, quelles sont les bonnes façons pour améliorer considérablement les performances?

pour la première question, imaginez que l'on vous remette un projet bien écrit et que vous devez améliorer vos performances, mais vous ne semblez pas pouvoir obtenir beaucoup de gain grâce au remaniement/optimisation. Que feriez-vous pour l'accélérer dans ce cas, à moins de le réécrire en C?

40
demandé sur Blorgbeard 2008-10-06 01:46:00

18 réponses

Concernant "Deuxièmement: Lors de l'écriture d'un programme à partir de zéro en python, quelles sont les bonnes façons d'améliorer considérablement les performances?"

Rappelez-vous la Jackson règles de l'optimisation:

  • Règle 1: ne le faites pas.
  • règle 2 (pour experts seulement): ne le faites pas encore.

Et le Knuth la règle:

  • " l'optimisation prématurée est la racine de tout mal."

les règles les plus utiles sont dans les règles générales pour L'optimisation .

  1. N'optimisent pas que vous allez. De la première à obtenir ce droit. Puis l'obtenir rapidement. L'optimisation d'un mauvais programme est toujours mal.

  2. souvenez-vous de la règle 80/20.

  3. Toujours "avant" et "après" points de référence. Sinon, vous ne savez pas si vous avez trouvé les 80%.

  4. utilisez les bons algorithmes et structures de données. Cette règle doit être la première. Rien n'importe autant que l'algorithme et la structure des données.

Bas De Ligne

vous ne pouvez pas empêcher ou éviter l'effort" optimiser ce programme". C'est une partie du travail. Vous devez planifier pour cela et le faire avec soin, tout comme la conception, le code et le test activité.

40
répondu S.Lott 2008-10-05 22:46:37

plutôt que de simplement pointer vers C, je suggérerais:

faites Compter votre code. Faire plus avec moins d'exécutions de lignes:

  • changez l'algorithme en un algorithme plus rapide. Il n'a pas besoin d'être fantaisiste pour être plus rapide dans de nombreux cas.
  • utilisez des primitives python qui se trouvent être écrites en C. Certaines choses forceront l'envoi d'un interprète là où d'autres ne le feront pas. Ce dernier est préférable
  • attention au code qui construit d'abord une structure de big data suivie de sa consommation. Pensez à la différence entre la portée et xrange. En général, il est souvent utile de réfléchir à l'utilisation de la mémoire du programme. L'utilisation de générateurs peut parfois amener O(n) l'utilisation de mémoire à O (1).
  • Python n'est généralement pas optimisé. Hisser le code invariant hors des boucles, éliminer les sous-expressions courantes lorsque possible dans les boucles serrées.
  • si quelque chose est coûteux, alors précomputez-le ou Mémorisez-le. Les expressions régulières peuvent être compilées par exemple.
  • besoin de faire des nombres? Vous devriez vérifier numpy .
  • beaucoup de programmes python sont lents parce qu'ils sont liés par l'entrée/sortie du disque ou l'accès à la base de données. Assurez-vous que vous avez quelque chose de Valable à faire pendant que vous attendez les données pour arriver plutôt que de simplement bloquer. Une arme pourrait être quelque chose comme le cadre Twisted .
  • noter que de nombreux les bibliothèques ont des versions C, que ce soit XML, JSON ou autre. Ils sont souvent beaucoup plus rapides que L'interpréteur Python.

si tout ce qui précède échoue pour le code profilé et mesuré, alors commencer à penser au chemin de réécriture de C.

26
répondu I GIVE CRAP ANSWERS 2008-10-06 02:28:52

les suspects habituels ... profile-le, trouve la ligne la plus chère, trouve ce qu'elle fait, répare-la. Si vous n'avez pas fait beaucoup de profilage avant, il pourrait y avoir de grosses boucles quadratiques ou de la duplication de chaîne se cachant derrière des expressions par ailleurs anodines.

en Python, deux des causes les plus courantes que j'ai trouvé pour le ralentissement non évident sont la concaténation de chaîne et les générateurs. Puisque les cordes de Python sont immuables, faire quelque chose comme ça:

result = u""
for item in my_list:
    result += unicode (item)

copiera la chaîne en entier deux fois par itération. Cela a été bien couvert, et la solution est d'utiliser "".join :

result = "".join (unicode (item) for item in my_list)
Les générateurs

sont un autre coupable. Ils sont très faciles à utiliser et peuvent simplifier certaines tâches énormément, mais un générateur mal appliqué sera beaucoup plus lent que simplement ajouter des éléments à une liste et retourner la liste.

enfin, ne soyez pas peur de réécrire des bits en C! Python, en tant que langage dynamique de haut niveau, n'est tout simplement pas capable de correspondre à la vitesse de C. S'il y a une fonction que vous ne pouvez plus optimiser en Python, envisagez de l'extraire dans un module d'extension.

ma technique préférée pour cela est de maintenir à la fois les versions Python et C d'un module. La version Python est écrite pour être aussi claire et évidente que possible -- tous les bogues doivent être faciles à diagnostiquer et à corriger. Écrivez vos tests à l'encontre de ce module. Ensuite, écrivez la version C et mettez-la à l'essai. Son comportement devrait dans tous les cas être le même que celui de L'implémentation Python -- s'ils diffèrent, il devrait être très facile de comprendre ce qui est faux et de corriger le problème.

23
répondu John Millikin 2008-10-05 22:09:25

première chose qui vient à l'esprit: psyco . Il fonctionne uniquement sur x86, pour le moment.

puis liaison constante . Qui est, faire toutes les références globales (et global.ATR , global.attr.attr ...) être des noms locaux à l'intérieur de fonctions et de méthodes. Ce n'est pas toujours réussi, mais en général ça marche. Cela peut être fait à la main, mais c'est évidemment fastidieux.

avez-vous dit en dehors de l'optimisation en code, donc je ne vais pas creuser dans ce domaine, mais garder votre esprit ouvert pour les erreurs typiques ( for i in range(10000000) vient à l'esprit) que les gens font.

17
répondu tzot 2011-09-03 03:40:03

Cython et pyrex peuvent être utilisés pour générer du code c en utilisant une syntaxe de type python. Psyco est également fantastique pour les projets appropriés (parfois vous ne remarquerez pas beaucoup de boost de vitesse, parfois il sera aussi 50x que rapide). Je pense toujours que la meilleure façon est de profiler votre code (cProfile, etc.) et puis il suffit de coder les goulots d'étranglement en tant que fonctions c pour python.

9
répondu hacama 2008-10-05 22:03:44

je suis surpris que personne n'ait mentionné ShedSkin: http://code.google.com/p/shedskin / , il convertit automagiquement votre programme python en C++ et dans certains benchmarks, il produit de meilleures améliorations que psyco en vitesse.

Plus des anecdotes sur la simplicité: http://pyinsci.blogspot.com/2006/12/trying-out-latest-release-of-shedskin.html

Il y a des limites bien, voir: http://tinyurl.com/shedskin-limitations

7
répondu torial 2008-10-05 22:54:57

j'espère que vous avez lu: http://wiki.python.org/moin/PythonSpeed/PerformanceTips

reprendre ce qui est déjà là sont généralement 3 principes:

  • écrire du code qui se transforme en un meilleur bytecode, comme, utiliser des locaux, éviter les recherches/appels inutiles, utiliser des constructions idiomatiques (s'il y a une syntaxe naturelle pour ce que vous voulez, utilisez - la-généralement plus rapide. par exemple: ne pas faire: "pour la clé dans some_dict.les touches()", faire "clé en un_dict")
  • tout ce qui est écrit en C est beaucoup plus rapide, abusez de toutes les fonctions/modules C disponibles
  • en cas de doute, importer timeit, profil
5
répondu ionelmc 2008-12-12 22:27:19

lancez votre application à travers le profileur Python. Trouver un goulot d'étranglement sérieux. Réécrivez ce goulot D'étranglement en C. Répéter.

4
répondu Vicent Marti 2008-10-05 22:02:52

les gens ont donné quelques bons conseils, mais vous devez être conscient que lorsque la haute performance est nécessaire, le modèle python est: punt à C. Des Efforts comme psyco peuvent aider un peu dans le futur, mais python n'est tout simplement pas un langage rapide, et il n'est pas conçu pour l'être. Très peu de langues ont la capacité de faire le truc dynamique vraiment bien et encore générer du code très rapide; au moins pour le futur prévisible (et certains des travaux de conception contre la compilation rapide) qui sera le cas.

donc, si vous vous retrouvez vraiment dans cette impasse, votre meilleure chance sera d'isoler les parties de votre système qui sont inacceptables, lents en (bon) python, et de concevoir autour de l'idée que vous allez réécrire ces bits en C. Désolé. Une bonne conception peut aider à rendre cela moins douloureux. Prototype il en python d'abord, puis vous avez facilement un contrôle de santé mentale sur votre c, ainsi.

Cela fonctionne assez bien pour des choses comme numpy, après tout. Je ne peux pas souligner assez combien une bonne conception vous aidera bien. Si vous frappez de façon itérative vos bits python et remplacez les plus lents par C, vous pourriez finir avec un gros gâchis. Pensez exactement où les bits C sont nécessaires, et comment ils peuvent être minimisés et encapsulés raisonnablement.

4
répondu simon 2008-10-05 22:27:08

cela n'accélérera pas nécessairement tout votre code, mais est une connaissance critique lors de la programmation en Python Si vous voulez éviter de ralentir votre code. Le "Global Interpreter Lock" (GIL), a le potentiel de réduire radicalement la vitesse de votre programme multi-threadé si son comportement n'est pas compris (oui, ce bit me ... J'avais une machine 4 processeurs sympa qui n'utiliserait pas plus de 1,2 processeurs à la fois). Il y a un article d'introduction avec quelques liens pour vous aider à commencer SmoothSpan .

4
répondu Steve Moyer 2008-10-05 22:36:07

juste une remarque sur l'utilisation de psyco: dans certains cas, il peut produire des temps d'exécution plus lents. Je ne me souviens pas de l'article que j'ai lu, mais les fonctions map() et reduce() ont été mentionnées spécifiquement. Heureusement, vous pouvez dire à psyco de ne pas gérer les fonctions et/ou modules spécifiés.

3
répondu Walter 2008-10-05 22:45:13

C'est la procédure que j'essaie de suivre:

  • importer psyco; psyco.plein()
  • si ce n'est pas assez rapide, lancez le code dans un profileur, voyez où sont les goulots d'étranglement. (Désactiver psyco pour cette étape!)
  • essayez de faire des choses comme d'autres personnes ont mentionné pour obtenir le code à ces goulots d'étranglement aussi vite que possible.
    • des Trucs comme [str(x) pour x dans l] ou [x.strip() pour x dans l] est beaucoup, beaucoup plus lent que la carte(str, x) ou d'une carte(str.bande, x).
  • après cela, si j'ai encore besoin de plus de vitesse, il est en fait très facile de mettre PyRex en marche. Je copie d'abord une section de code python, je la mets directement dans le code pyrex, et je vois ce qui se passe. Puis je la tourne en rond jusqu'à ce qu'elle devienne de plus en plus rapide.
3
répondu Claudiu 2008-10-06 01:38:57

il est souvent possible d'atteindre des vitesses proches de C (assez proches pour n'importe quel projet utilisant Python en premier lieu!) en remplaçant les algorithmes explicites écrits en longhand en Python par un algorithme implicite utilisant un appel Python intégré. Cela fonctionne parce que la plupart des built-ins de Python sont écrits en C de toute façon. Eh bien, à CPython bien sûr ; -) https://www.python.org/doc/essays/list2str/

3
répondu sep332 2014-11-14 01:43:27

la référence canonique à la façon d'améliorer le code Python est ici: PerformanceTips . Je déconseille l'optimisation en C, sauf si vous en avez vraiment besoin. Pour la plupart des applications, vous pouvez obtenir la performance dont vous avez besoin en suivant les règles affichées dans ce lien.

2
répondu Jason Baker 2008-10-29 17:16:39

si vous utilisez psyco, je recommande psyco.profile() au lieu de psyco.full() . Pour un projet plus vaste, il sera plus intelligent sur les fonctions qui ont été optimisées et utiliser une tonne de moins de mémoire.

je recommande aussi d'examiner les itérateurs et les générateurs. Si votre application utilise de grands ensembles de données, cela vous permettra d'économiser de nombreuses copies de conteneurs.

1
répondu Peter Shinners 2008-10-06 17:24:16

outre le (grand) psyco et le (nice) shedskin , je recommande d'essayer cython une grande fourchette de pyrex .

Ou, si vous n'êtes pas pressé, je vous recommande d'attendre. De nouvelles machines virtuelles python arrivent, et unladen-swallow trouvera son chemin dans le courant dominant.

1
répondu Davide 2009-05-14 15:15:48

quelques façons d'accélérer le code Python ont été introduites après que cette question a été posée:

  • Pypy a un JIT-compilateur, ce qui le rend beaucoup plus rapide pour le code CPU-lié.
  • Pypy est écrit dans Rpython , un sous-ensemble de Python qui compile vers le code natif, en s'appuyant sur la chaîne D'outils LLVM.
0
répondu Janus Troelsen 2013-09-17 12:20:41

pour un projet établi, je pense que le principal gain de performance sera de faire usage de python lib interne autant que possible.

quelques conseils sont ici: http://blog.hackerearth.com/faster-python-code

0
répondu joydeep bhattacharjee 2017-01-16 07:33:22