869 votes

Pourquoi code Python court plus vite dans une fonction ?

<pre><code></code><p>Ce morceau de code en Python s’exécute en </p><pre><code></code></pre><p><pre><code></code></pre><p>puis, elle s’exécute depuis beaucoup plus longtemps :</p><pre><code></code></pre><p>Pourquoi est-ce ?</p><p>Remarque : La synchronisation se faite avec la fonction de départ en BASH sous Linux.</p></pre>

666voto

ecatmur Points 64173

L'intérieur d'une fonction, le bytecode est

  2           0 SETUP_LOOP              20 (to 23)
              3 LOAD_GLOBAL              0 (xrange)
              6 LOAD_CONST               3 (100000000)
              9 CALL_FUNCTION            1
             12 GET_ITER            
        >>   13 FOR_ITER                 6 (to 22)
             16 STORE_FAST               0 (i)

  3          19 JUMP_ABSOLUTE           13
        >>   22 POP_BLOCK           
        >>   23 LOAD_CONST               0 (None)
             26 RETURN_VALUE        

Au haut niveau, le bytecode est

  1           0 SETUP_LOOP              20 (to 23)
              3 LOAD_NAME                0 (xrange)
              6 LOAD_CONST               3 (100000000)
              9 CALL_FUNCTION            1
             12 GET_ITER            
        >>   13 FOR_ITER                 6 (to 22)
             16 STORE_NAME               1 (i)

  2          19 JUMP_ABSOLUTE           13
        >>   22 POP_BLOCK           
        >>   23 LOAD_CONST               2 (None)
             26 RETURN_VALUE        

La différence est que, STORE_FAST est plus rapide (!) qu' STORE_NAME. C'est parce que dans une fonction, i est local, mais au niveau supérieur, il est mondial.

Pour examiner le bytecode, utilisez l' dis module. J'ai pu démonter la fonction directement, mais de démonter le toplevel code que j'ai eu à utiliser l' compile builtin.

556voto

katrielalex Points 40655

Vous pourriez vous demander pourquoi il est plus rapide pour stocker les variables locales que globales. C'est un Disponible détail d'implémentation.

Rappelez-vous que Disponible est compilé en bytecode, qui l'interprète exécute. Lorsqu'une fonction est compilé, les variables locales sont stockées dans un tableau de taille fixe (pas un dict) et les noms de variables sont affectées à l'index. Cela est possible parce que vous ne pouvez pas ajouter dynamiquement des variables locales à une fonction. Puis récupérer une variable locale est littéralement un pointeur de recherche dans la liste et le refcount augmentation sur l' PyObject ce qui est futile.

Cela contraste global de recherche (LOAD_GLOBAL), ce qui est un vrai dict de recherche impliquant un hachage et ainsi de suite. D'ailleurs, c'est pourquoi vous avez besoin de spécifier global i si vous voulez qu'il soit global: si jamais vous affecter à une variable à l'intérieur d'un champ, le compilateur émet STORE_FASTs pour son accès, sauf si vous lui dites de ne pas.

Par le moyen global des recherches sont encore assez optimisé. L'attribut id favoris foo.bar sont vraiment lent!

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