46 votes

Accélérer Python

Il s'agit en fait de deux questions, mais elles se ressemblent tellement que, pour rester simple, je me suis dit que j'allais les regrouper :

  • Tout d'abord : Dans le cas d'un projet python bien établi, quels sont les moyens d'accélérer le projet au-delà de la simple optimisation du code ?

  • Ensuite, : Lorsque vous écrivez un programme à partir de zéro en python, quels sont les bons moyens d'améliorer considérablement les performances ?

Pour la première question, imaginez que l'on vous remette un projet bien écrit et que vous ayez besoin d'améliorer les performances, mais que vous ne parveniez pas à obtenir un gain important par le biais d'un remaniement/optimisation. Que feriez-vous pour accélérer le projet dans ce cas, à moins de le réécrire en quelque chose comme le C ?

42voto

S.Lott Points 207588

Concernant "Deuxièmement : Lors de l'écriture d'un programme à partir de zéro en python, quels sont les bons moyens d'améliorer considérablement les performances ?".

Rappelez-vous les règles d'optimisation de Jackson :

  • Règle 1 : Ne le faites pas.
  • Règle 2 (pour les experts uniquement) : Ne le faites pas encore.

Et la règle de Knuth :

  • "L'optimisation prématurée est la racine de tous les maux."

Les règles les plus utiles se trouvent dans le Règles générales d'optimisation .

  1. N'optimisez pas au fur et à mesure. Commencez par bien faire les choses. Ensuite, faites-le rapidement. Optimiser un mauvais programme est toujours mauvais.

  2. Rappelez-vous la règle des 80/20.

  3. Effectuez toujours des tests de référence "avant" et "après". Sinon, vous ne saurez pas si vous avez trouvé les 80 %.

  4. Utilisez les bons algorithmes et les bonnes structures de données. Cette règle devrait être la première. Rien ne compte autant que l'algorithme et la structure de données.

Ligne de fond

Vous ne pouvez pas prévenir ou éviter l'effort d'"optimisation de ce programme". Cela fait partie du travail. Vous devez le planifier et le faire avec soin, tout comme les activités de conception, de codage et de test.

0 votes

28voto

I GIVE CRAP ANSWERS Points 12429

Plutôt que de faire un coup de poing à C, je dirais :

Faites en sorte que votre code compte. Faites plus avec moins d'exécutions de lignes :

  • Changez l'algorithme pour un plus rapide. Il n'a pas besoin d'être sophistiqué pour être plus rapide dans de nombreux cas.
  • Utiliser des primitives python qui se trouvent être écrites en C. Certaines choses forceront l'interpréteur à les distribuer, d'autres non. Ces dernières sont préférables
  • Méfiez-vous du code qui construit d'abord une grosse structure de données puis la consomme. Pensez à la différence entre range 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 ramener l'utilisation de la mémoire de O(n) à O(1).
  • Python est généralement non optimisé. Soulevez le code invariant hors des boucles, éliminez les sous-expressions communes lorsque cela est possible dans les boucles serrées.
  • Si quelque chose est coûteux, il faut le précalculer ou le mémoriser. Les expressions régulières peuvent être compilées par exemple.
  • Vous avez besoin de faire des calculs ? Vous pourriez vouloir vérifier numpy dehors.
  • De nombreux programmes python sont lents parce qu'ils sont limités par les entrées/sorties de disque ou l'accès aux bases de données. Assurez-vous d'avoir quelque chose d'intéressant à faire pendant que vous attendez l'arrivée des données plutôt que de vous contenter de bloquer. Une arme pourrait être quelque chose comme le Twisted cadre.
  • Notez que de nombreuses bibliothèques de traitement de données cruciales ont des versions C, qu'il s'agisse de XML, JSON ou autre. Elles sont souvent beaucoup plus rapides que l'interpréteur Python.

Si tout ce qui précède échoue pour le code profilé et mesuré, commencez à réfléchir à la voie de la réécriture du C.

1 votes

De nos jours, les pandas ( pandas.pydata.org ) devrait être ajouté à cette partie de calcul, je pense.

24voto

John Millikin Points 86775

Les suspects habituels - le profiler, trouver la ligne la plus chère, comprendre ce qu'elle fait, la réparer. Si vous n'avez pas fait beaucoup de profilage auparavant, il se peut que de grosses boucles quadratiques ou des doublons de chaînes se cachent derrière des expressions d'apparence inoffensive.

En Python, deux des causes les plus courantes que j'ai trouvées pour un ralentissement non évident sont la concaténation de chaînes et les générateurs. Puisque les chaînes de caractères de Python sont immuables, faire quelque chose comme ceci :

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

copiera le tout le site deux fois par itération. Ce problème a été bien traité, et la solution consiste à utiliser la méthode suivante "".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 énormément certaines tâches, mais un générateur mal appliqué sera beaucoup plus lent que le simple fait d'ajouter des éléments à une liste et de renvoyer cette liste.

Enfin, n'ayez pas peur de réécrire les bits en C ! Python, en tant que langage dynamique de haut niveau, n'est tout simplement pas capable d'égaler la vitesse du C. S'il y a une fonction que vous ne pouvez plus optimiser en Python, envisagez de l'extraire vers un module d'extension.

Ma technique préférée pour cela est de maintenir les versions Python et C d'un module. La version Python est écrite de manière à être aussi claire et évidente que possible - tout bogue doit être facile à diagnostiquer et à corriger. Ecrivez vos tests pour ce module. Ensuite, écrivez la version C, et testez-la. Son comportement devrait dans tous les cas être égal à celui de l'implémentation Python -- s'ils diffèrent, il devrait être très facile de déterminer lequel est mauvais et de corriger le problème.

0 votes

La concaténation de chaînes de caractères n'est pas si mauvaise en Python 2.5. Point de données sur les générateurs : 2:1 (v2.5.2), 1,5:1,5 (v3.0) - liste contre générateurs pour une fonction gourmande en ressources processeur que j'ai testée hier (les performances sont les mêmes sur py3k, les générateurs sont moins performants sur v2.5).

3 votes

Pour ajouter à ce commentaire : la raison pour laquelle la concaténation de chaînes n'est pas si mauvaise en 2.5 (et 2.6) est qu'il existe une optimisation spécifique pour ce cas dans CPython (mais pas nécessairement dans toute autre implémentation de Python).

0 votes

Tony, pouvez-vous fournir des détails sur l'optimisation ?

17voto

tzot Points 32224

La première chose qui me vient à l'esprit : psyco . Il ne fonctionne que sur x86, pour l'instant.

Ensuite, liaison constante . C'est-à-dire que toutes les références globales (et global.attr , global.attr.attr ) sont des noms locaux à l'intérieur des fonctions et des méthodes. Ce n'est pas toujours réussi, mais en général cela fonctionne. Cela peut être fait à la main, mais c'est évidemment fastidieux.

Vous avez dit qu'à part l'optimisation en code, je ne m'y attarderai pas, mais gardez l'esprit ouvert aux erreurs typiques ( for i in range(10000000) me vient à l'esprit) que les gens font.

0 votes

+1 Je viens d'essayer le psyco et c'est incroyable ! Incroyablement facile à utiliser, et incroyablement efficace (YMMV, voir son site web).

9voto

hacama Points 211

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 de gain de vitesse, parfois il sera jusqu'à 50x plus rapide). Je pense toujours que le meilleur moyen est de profiler votre code (cProfile, etc.) et ensuite de coder les goulots d'étranglement comme des fonctions c pour python.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X