Stavo cercando di ottimizzare un programma con cui sto armeggiando, quando ho notato che fare value = i % 65536
sembrava rallentare, quindi fare value = i % (2**16)
.Perché sta prendendo la mod di un numero in python più veloce con gli esponenti?
Per verificare ciò, ho eseguito il seguente programma:
import cProfile
import pstats
AMOUNT = 100000000
def test1():
for i in xrange(AMOUNT):
value = i % 65536
return
def test2():
for i in xrange(AMOUNT):
value = i % (256**2)
return
def test3():
for i in xrange(AMOUNT):
value = i % (16**4)
return
def test4():
for i in xrange(AMOUNT):
value = i % (4**8)
return
def test5():
for i in xrange(AMOUNT):
value = i % (2**16)
return
def run_tests():
test1()
test2()
test3()
test4()
test5()
return
if __name__ == '__main__':
cProfile.run('run_tests()', 'results')
stats = pstats.Stats('results')
stats.sort_stats('calls', 'nfl')
stats.print_stats()
... che ha prodotto il seguente risultato:
Fri May 11 15:11:59 2012 results
8 function calls in 40.473 seconds
Ordered by: call count, name/file/line
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.000 0.000 40.473 40.473 <string>:1(<module>)
1 0.000 0.000 40.473 40.473 test.py:31(run_tests)
1 10.466 10.466 10.466 10.466 test.py:6(test1)
1 7.475 7.475 7.475 7.475 test.py:11(test2)
1 7.485 7.485 7.485 7.485 test.py:16(test3)
1 7.539 7.539 7.539 7.539 test.py:21(test4)
1 7.508 7.508 7.508 7.508 test.py:26(test5)
Utilizzando 65536
era il più lento a 10.466 secondi, mentre si fa 256**2
era il più veloce a 7.475 secondi (con gli altri possibili valori di esponente in mezzo). Certo, questa differenza di velocità è evidente solo in presenza di elevate quantità di ripetizioni, ma sono ancora curioso di sapere perché questo si verifica.
Perché il numero di un numero di 65536
è più lento, quindi il mod viene utilizzato dagli esponenti? Dovrebbero valutare lo stesso numero e avrei pensato che ci sarebbe voluto più tempo prima che l'interprete python valutasse completamente gli esponenti prima di prendere il mod.
Per estensione, è generalmente più efficiente utilizzare le potenze di due in espressioni python piuttosto che digitare completamente il numero in uscita? E questo modello vale per le operazioni oltre al modulo o per altri numeri oltre allo 2
?
(btw, sto usando Python 2.7.2 (32 bit), e ho eseguito quanto sopra su un laptop Windows 7 a 64 bit).
EDIT:
così ho provato invertendo l'ordine delle funzioni che io chiamo, e ora è vero il contrario. Sembra che qualunque sia la prima funzione in run_tests
sarà sempre un po 'più lenta quando si usa cProfile, che è strano. Quindi, lezione appresa, immagino - i profiler sono strani: D
Questo è piuttosto interessante, ma si noti che la differenza nei risultati per i test 2 - 5 non è molto significativa. Cosa succede se esegui i test in ordine inverso? – Oliver
Si sta chiamando la funzione solo una volta, quindi mi preoccuperei di qualche tipo di overhead di profiler o qualcosa del genere. Non vedo questo effetto usando '% timeit' di IPython .... – Dougal
Impossibile riprodurre questo effetto con Python 2.7.3 su Linux x86-64. –