2010-08-23 10 views
17

J'ai joué avec un décorateur de synchronisation pour mon application pylônes afin de fournir des informations sur le timing de vol pour des fonctions spécifiques. Je l'ai fait en créant un décorateur & en le reliant simplement à n'importe quelle fonction dans le contrôleur que je veux chronométré.Combien de frais généraux les décorateurs ajoutent-ils aux appels de fonction Python

Il a été souligné cependant que les décorateurs pourraient ajouter une bonne quantité de frais généraux à l'appel, et qu'ils courent 2-3 fois plus lentement qu'une fonction non décorée. Premièrement, je m'attendrais à ce que l'exécution d'une fonction décorée prenne un coup plus long que celui d'une fonction non décorée, mais je m'attendrais à ce que le temps système soit dans les millièmes de secondes négligeable par rapport à un appel d'insertion SQL. Le décorateur lui-même fait de simples calculs de synchronisation simples en utilisant time.time() & une agrégation très simple.

Est-ce que les décorateurs ajoutent des frais généraux importants à un système? Je ne trouve rien pour soutenir ça.

+5

Les frais généraux de la décoration elle-même est mesurable, mais nulle part près de 2-3x. Cela ne prend pas en compte le comportement de décoration, qui peut prendre beaucoup de temps en fonction de ce que vous faites (mises à jour de la base de données, signaux de rebond de la lune, etc.). – PaulMcG

+1

+1 pour renvoyer des signaux hors de la lune –

+0

De même, mais en réservant +2 pour un commentaire futur: "synchrone moon-signal-bouncing" – Profane

Répondre

13

La surcharge ajoutée à l'aide d'un décorateur ne devrait être qu'un appel de fonction supplémentaire.

Le travail effectué par le décorateur ne fait pas partie de l'overhead car votre alternative est d'ajouter le code équivalent à l'objet décoré.

Il est donc possible que la fonction décorer dure deux fois plus longtemps, mais c'est parce que le décorateur effectue un travail important qui prend à peu près le même temps que la fonction non décorée.

+5

Upvote pour la faute de frappe. – Dolph

5

Ce qui est important de savoir est qu'un décorateur a un effet simple:

@decorator 
def f(): 
    … 

est juste du sucre syntaxique pour

def f(): 
    … 
f = decorator(f) 

Ainsi, si décorateur ne fait rien, vous n'avez pas tout frais généraux lorsque appelant la fonction décorée (l'appel decorator(f) prend un peu de temps, cependant), comme dans

decorator = lambda func: func 
@decorator 
def f(): 
    … 

Si le décorateur fait quelque chose, vous n'obtenez que le temps nécessaire au décorateur. Cela inclut généralement un appel de fonction supplémentaire (celle de la fonction décorée), comme dans

def decorator(func): 
    def decorated_func(): 
     print "Before calling function", func # Some overhead (but that's normal) 
     func() # This will be a second function call, after the call to decorated_func() 
    return decorated_func 

Ainsi, en soi, la décoration d'une fonction n'ajoute pas de frais généraux pour ce que vous voulez faire: la seule tête évident que vous pourrait en principe supprimer serait de ne pas appeler func() dans la fonction décorée mais copier plutôt son code complet, mais la lisibilité du code en souffrirait (la lisibilité et la flexibilité sont quelques-unes des raisons pour lesquelles les décorateurs existent en premier lieu).

+0

-1 La surcharge de l'appel de fonction en Python n'est pas négligeable. Et suggérer que l'on réplique le code de 'func()' dans le décorateur détruit tout le point d'un décorateur en premier lieu. Si quelque chose, je préfère reproduire le code du décorateur dans 'func()', mais encore une fois, si nous faisons cela, la simplicité d'utilisation du décorateur est vaincue et le code 'func()' est pollué par le comportement de décoration . Vous ne pouvez vraiment pas dire "si le décorateur ne fait rien, vous n'avez pas de frais généraux". Les décorateurs sont utiles pour le traçage de code, etc., mais ils se font au prix d'un appel de fonction supplémentaire à l'exécution. – PaulMcG

+0

@Paul: En effet, la surcharge de l'appel de fonction est relativement significative en Python (jamais dit autrement!). Et je suis d'accord avec le fait que mettre le code 'func()' dans le décorateur détruit tout le point d'un décoré (comme je l'ai écrit). Nous sommes donc entièrement d'accord! Je ne faisais que donner des points clés qui permettent à l'affiche originale de comprendre exactement d'où vient le surcoût d'un décorateur. – EOL

+0

Mon principal argument était avec votre déclaration "si le décorateur ne fait rien, vous n'avez aucun frais généraux," qui semblait que vous étiez en train de négliger l'appel de fonction supplémentaire. Je suis allé enlever mon downvote, mais SO ne me laissera pas à moins que vous fassiez des modifications à votre réponse. – PaulMcG

4

Est-ce que les décorateurs ajoutent des frais généraux importants à un système? Je ne trouve rien pour soutenir ça.

Ils ajoutent presque aucun frais généraux mesurables. Zéro.

Il est important de noter que le décorateur court une fois pour créer la fonction décorée. Une fois.

La fonction décorée comporte deux parties.

  1. la décoration a été ajoutée. Ce n'est pas frais généraux.

  2. plus la fonction d'origine. Ce n'est pas frais généraux.

Il n'y a pas vraiment de frais généraux. Vous pourriez - avec un peu de soin - être capable de mesurer le surcoût d'une fonction supplémentaire call-and-return dans le cadre d'une fonction décorée, mais c'est presque infiniment petit. Et c'est probablement beaucoup moins qu'un design alternatif qui n'utilise pas la décoration.

Questions connexes