2011-03-30 5 views
3

Quelqu'un peut-il m'expliquer pourquoi cela se passe?Python timeit ne fonctionne pas?

[email protected] ~ $ time python /usr/lib64/python2.7/timeit.py -n 1 \ 
    -- 'x = 10**1000' 
1 loops, best of 3: 0.954 usec per loop 

real 0m0.055s 
user 0m0.050s 
sys  0m0.000s 

[email protected] ~ $ time python /usr/lib64/python2.7/timeit.py -n 1 \ 
    -- 'x = 10**100000' 
1 loops, best of 3: 0.954 usec per loop 

real 0m0.067s 
user 0m0.040s 
sys  0m0.020s 

[email protected] ~ $ time python /usr/lib64/python2.7/timeit.py -n 1 \ 
    -- 'x = 10**10000000' 
1 loops, best of 3: 0.954 usec per loop 

real 0m20.802s 
user 0m20.540s 
sys  0m0.170s 

-je obtenir exactement le même résultat de timeit, mais time me dit que l'évaluation 10**10000000 prend plus de 20 secondes. La même chose arrive si je l'appelle timeit de l'interprète:

>>> t = time.time() 
>>> print timeit.timeit('x = 10**10000000;', number=1) 
5.00679016113e-06 
>>> print time.time() - t 
20.6168580055 

Pourquoi mon timeit ne fonctionne pas, ou ce que je fais mal?

Informations complémentaires:

>>> print sys.version 
2.7.1+ (2.7:4f07cacb2c3b+, Mar 28 2011, 23:11:59) 
[GCC 4.4.5] 

>>> print sys.version_info 
>>> sys.version_info(major=2, minor=7, micro=2, releaselevel='alpha', serial=0) 

MISE À JOUR:

Voici une autre observation très intéressante:

>>> def run(): 
...  t = time.time() 
...  x = 10**10000000 
...  print time.time() - t 

Quand j'appuyez sur Entrée après la définition de cette fonction, il faut environ une demi-minute jusqu'à ce que je revienne à une invite. Et puis:

>>> run() 
2.14576721191e-06 

Pourquoi cela se produit-il? Le corps de la fonction est-il pré-compilé ou optimisé d'une manière ou d'une autre?

Répondre

5

Je suppose que le problème réside dans la façon dont vous définissez le problème à timeit. Je pense que ce qui se passe est que l'expression est évaluée une fois lorsque l'expression du test est compilée, puis regardée (plutôt que réévaluée) avec chaque boucle timeit. Donc actuellement tout ce que vous mesurez est le temps qu'il faut pour faire l'assignation plutôt que le calcul.

Vous aurez besoin de forcer le calcul arriver à chaque fois:

timeit.timeit('x = 10; y = 100; z = x ** y') 

Edit: en réponse à votre question plus tard, le corps de la fonction est en cours d'optimisation. Le compilateur voit 10*100000 et se rend compte qu'il ne changera jamais alors il calcule au moment de la compilation plutôt que de l'exécution.

+0

Vous avez raison, en forçant le calcul à se produire chaque fois que cela prend plus de temps. Je ne savais pas que Python va pré-calculer les expressions pour moi. –

+0

@Attila - moi non plus jusqu'à présent. –

4

Comparez:

>>> import dis 
>>> def run(): 
...  return 10**100 
... 
>>> dis.dis(run) 
    3   0 LOAD_CONST    3 (100000000000000000000000000000000000 
00000000000000000000000000000000000000000000000000000000000000000L) 
       3 RETURN_VALUE   

Et

>>> def runvar(): 
...  x = 10 
...  return x**100 
... 
>>> dis.dis(runvar) 
    3   0 LOAD_CONST    1 (10) 
       3 STORE_FAST    0 (x) 

    4   6 LOAD_FAST    0 (x) 
       9 LOAD_CONST    2 (100) 
      12 BINARY_POWER   
      13 RETURN_VALUE   

Notez que BINARY_POWER est exécuté lors de l'exécution que dans le second cas. Donc, timeit se comporte comme il se doit.