web-dev-qa-db-fra.com

Utilisation du principe de responsabilité unique (SRP) dans Python lorsque les appels sont coûteux

Quelques points de base:

  • Les appels de méthode Python sont "chers" en raison de leur nature interprétée . En théorie, si votre code est assez simple, décomposer Python a un impact négatif en plus de la lisibilité et de la réutilisation ( ce qui est un gros gain pour les développeurs, pas tant pour les utilisateurs).
  • Le principe de responsabilité unique (SRP) maintient le code lisible, est plus facile à tester et à maintenir.
  • Le projet a un arrière-plan spécial où nous voulons du code lisible, des tests, des performances temporelles et.

Par exemple, un code comme celui-ci qui invoque plusieurs méthodes (x4) est plus lent que le suivant qui n'en est qu'une.

from operator import add

class Vector:
    def __init__(self,list_of_3):
        self.coordinates = list_of_3

    def move(self,movement):
        self.coordinates = list( map(add, self.coordinates, movement))
        return self.coordinates

    def revert(self):
        self.coordinates = self.coordinates[::-1]
        return self.coordinates

    def get_coordinates(self):
        return self.coordinates

## Operation with one vector
vec3 = Vector([1,2,3])
vec3.move([1,1,1])
vec3.revert()
vec3.get_coordinates()

Par rapport à cela:

from operator import add

def move_and_revert_and_return(vector,movement):
    return list( map(add, vector, movement) )[::-1]

move_and_revert_and_return([1,2,3],[1,1,1])

Si je dois paralléliser quelque chose comme ça, c'est assez objectif de perdre des performances. Attention, ce n'est qu'un exemple; mon projet a plusieurs mini routines avec des mathématiques comme ça - Bien qu'il soit beaucoup plus facile de travailler avec, nos profileurs ne l'aiment pas.


Comment et où adopter le SRP sans compromettre les performances en Python, car son implémentation inhérente a un impact direct sur lui?

Existe-t-il des solutions de contournement, comme une sorte de pré-processeur qui met les choses en ligne pour la sortie?

Ou est Python tout simplement mauvais pour gérer la décomposition du code?

12
lucasgcb

Python est-il tout simplement insuffisant pour gérer la décomposition du code?

Malheureusement oui, Python est lent et il existe de nombreuses anecdotes sur les gens qui augmentent considérablement les performances en intégrant des fonctions et en rendant leur code laid.

Il existe un travail autour, Cython, qui est une version compilée de Python et beaucoup plus rapide.

- Modifier Je voulais juste répondre à certains des commentaires et autres réponses. Bien que leur poussée ne soit peut-être pas python spécifique. Mais optimisation plus générale.

  1. N'optimisez pas jusqu'à ce que vous ayez un problème, puis recherchez les goulots d'étranglement

    Généralement de bons conseils. Mais l'hypothèse est que le code "normal" est généralement performant. Ce n'est pas toujours le cas. Les langages et les cadres individuels ont chacun leurs propres particularités. Dans ce cas, les appels de fonction.

  2. Ce n'est que quelques millisecondes, d'autres choses seront plus lentes

    Si vous exécutez votre code sur un ordinateur de bureau puissant, vous ne vous en souciez probablement pas tant que votre code d'utilisateur unique s'exécute en quelques secondes.

    Mais le code métier a tendance à fonctionner pour plusieurs utilisateurs et nécessite plus d'une machine pour prendre en charge la charge. Si votre code s'exécute deux fois plus vite, cela signifie que vous pouvez avoir deux fois plus d'utilisateurs ou la moitié du nombre de machines.

    Si vous êtes propriétaire de vos machines et de votre centre de données, vous disposez généralement d'une grande partie des frais généraux liés à la puissance du processeur. Si votre code est un peu lent, vous pouvez l'absorber, au moins jusqu'à ce que vous ayez besoin d'acheter une deuxième machine.

    En ces jours de cloud computing où vous n'utilisez que la puissance de calcul dont vous avez besoin et pas plus, il y a un coût direct pour le code non performant.

    L'amélioration des performances peut réduire considérablement les dépenses principales d'une entreprise basée sur le cloud et les performances devraient être au premier plan.

17
Ewan

De nombreux problèmes de performances potentiels ne sont pas vraiment un problème dans la pratique. Le problème que vous soulevez peut être l'un d'entre eux. Dans la langue vernaculaire, nous appelons s'inquiéter de ces problèmes sans preuve qu'il s'agit de problèmes réels d'optimisation prématurée.

Si vous écrivez un frontal pour un service Web, vos performances ne seront pas affectées de manière significative par les appels de fonction, car le coût d'envoi de données sur un réseau dépasse de loin le temps nécessaire pour effectuer un appel de méthode.

Si vous écrivez une boucle serrée qui rafraîchit un écran vidéo soixante fois par seconde, cela peut avoir de l'importance. Mais à ce stade, je prétends que vous avez des problèmes plus importants si vous essayez d'utiliser Python pour ce faire, un travail pour lequel Python n'est probablement pas bien) -Convient.

Comme toujours, la façon dont vous le découvrez est de mesurer. Exécutez un profileur de performances ou des minuteries sur votre code. Voyez si c'est un vrai problème dans la pratique.


Le principe de responsabilité unique n'est pas une loi ou un mandat; c'est une ligne directrice ou un principe. La conception de logiciels est toujours une question de compromis; il n'y a pas d'absolu. Il n'est pas rare de compromis la lisibilité et/ou la maintenabilité pour la vitesse, vous devrez donc peut-être sacrifier SRP sur l'autel de la performance. Mais ne faites pas ce compromis sauf si vous savez vous avez un problème de performances.

50
Robert Harvey

Tout d'abord, quelques clarifications: Python est un langage. Il existe plusieurs interpréteurs différents qui peuvent exécuter du code écrit dans le langage Python. L'implémentation de référence (CPython) est généralement ce qui est référencé lorsque quelqu'un parle de "Python" comme s'il s'agissait d'une implémentation, mais il est important d'être précis lorsque l'on parle des caractéristiques de performances, car elles peuvent différer énormément entre les implémentations.

Comment et où adopter le SRP sans compromettre les performances en Python, car sa mise en œuvre inhérente le touche directement?

Cas 1.) Si vous avez du code Python pur (<= Python) La version 3.5, 3.6 du langage prend en charge le "niveau bêta") qui ne repose que sur des modules purs Python, vous pouvez adopter SRP partout et utiliser PyPy pour l'exécuter. PyPy ( https://morepypy.blogspot.com/2019/03/pypy-v71-released-now-uses-utf-8.html ) est un Python qui a un compilateur Just in Time (JIT) et peut supprimer la surcharge d'appel de fonction tant qu'il dispose de suffisamment de temps pour "se réchauffer" en traçant le code exécuté (quelques secondes IIRC).

Si vous êtes limité à utiliser l'interpréteur CPython, vous pouvez extraire les fonctions lentes dans des extensions écrites en C, qui seront précompilées et ne souffriront d'aucune surcharge d'interpréteur. Vous pouvez toujours utiliser SRP partout, mais votre code sera divisé entre Python et C. Que ce soit meilleur ou pire pour la maintenabilité que d'abandonner sélectivement SRP mais de ne s'en tenir qu'à Python le code dépend de votre équipe, mais si vous avez des sections critiques de performances de votre code, il sera sans aucun doute plus rapide que le code pur Python interprété par CPython le plus optimisé. Beaucoup des plus rapides de Python les bibliothèques mathématiques utilisent cette méthode (numpy et scipy IIRC). Ce qui est une belle séquence dans le cas 2 ...

Cas 2.) Si vous avez Python code qui utilise des extensions C (ou s'appuie sur des bibliothèques qui utilisent des extensions C) , PyPy peut être utile ou non selon la façon dont il est écrit. Voir http://doc.pypy.org/en/latest/extending.html pour plus de détails, mais le résumé est que CFFI a une surcharge minimale alors que CTypes est plus lent (l'utiliser avec PyPy peut être encore plus lent que CPython)

Cython ( https://cython.org/ ) est une autre option avec laquelle je n'ai pas autant d'expérience. Je le mentionne par souci d'exhaustivité afin que ma réponse puisse "se suffire à elle-même", mais ne revendique aucune expertise. De par mon utilisation limitée, j'ai eu l'impression de devoir travailler plus dur pour obtenir les mêmes améliorations de vitesse que je pouvais obtenir "gratuitement" avec PyPy, et si j'avais besoin de quelque chose de mieux que PyPy, il était tout aussi facile d'écrire ma propre extension C ( ce qui a l'avantage si je réutilise le code ailleurs ou en extrait une partie dans une bibliothèque, tout mon code peut toujours être exécuté sous n'importe quel interpréteur Python et il n'est pas nécessaire qu'il soit exécuté par Cython) .

J'ai peur d'être "enfermé" dans Cython, alors que tout code écrit pour PyPy peut également s'exécuter sous CPython.

** Quelques notes supplémentaires sur PyPy en production

Soyez très prudent lorsque vous faites des choix qui ont pour effet pratique de "vous enfermer" dans PyPy dans une grande base de code. Parce que certaines bibliothèques tierces (très populaires et utiles) ne jouent pas Nice pour les raisons mentionnées précédemment, cela peut entraîner des décisions très difficiles plus tard si vous réalisez que vous avez besoin de l'une de ces bibliothèques. Mon expérience consiste principalement à utiliser PyPy pour accélérer certains (mais pas tous) les microservices qui sont sensibles aux performances dans un environnement d'entreprise où il ajoute une complexité négligeable à notre environnement de production (nous avons déjà plusieurs langues déployées, certaines avec différentes versions majeures comme 2,7 vs 3.5 fonctionne quand même).

J'ai trouvé que l'utilisation de PyPy et de CPython m'obligeait régulièrement à écrire du code qui ne repose que sur les garanties apportées par la spécification du langage lui-même, et non sur les détails d'implémentation qui sont susceptibles de changer à tout moment. Vous pouvez trouver que penser à de tels détails est un fardeau supplémentaire, mais je l'ai trouvé précieux dans mon développement professionnel, et je pense que c'est "sain" pour l'écosystème Python dans son ensemble).

2
Steven Jackson