Ho cercato di capire perché Python 3 in realtà richiede molto tempo rispetto a Python 2 in alcune situazioni, di seguito sono pochi i casi che ho verificato da Python 3.4 a python 2.7.Perché Python 3 è notevolmente più lento di Python 2?
Nota: ho risposto ad alcune domande come Why is there no xrange function in Python3? e loop in python3 much slower than python2 e Same code slower in Python3 as compared to Python2, ma ritengo di non aver ottenuto il vero motivo alla base di questo problema.
Ho provato questo pezzo di codice per mostrare come si sta facendo la differenza:
MAX_NUM = 3*10**7
# This is to make compatible with py3.4.
try:
xrange
except:
xrange = range
def foo():
i = MAX_NUM
while i> 0:
i -= 1
def foo_for():
for i in xrange(MAX_NUM):
pass
Quando ho provato a fare funzionare questo programma con py3.4 e py2.7 ho seguito risultati .
Nota: queste statistiche sono passate attraverso una macchina 64 bit
con processore 2.6Ghz
e hanno calcolato l'ora utilizzando time.time()
in un unico ciclo.
Output : Python 3.4
-----------------
2.6392083168029785
0.9724123477935791
Output: Python 2.7
------------------
1.5131521225
0.475143909454
Io davvero non credo che ci sia stata modifiche applicate ai while
o xrange
2,7-3,4, so range
è stato avviato in qualità di xrange
in py3.4 ma come documentazione dice
range()
ora si comporta comexrange()
utilizzato per comportarsi, tranne che funziona con valori di dimensione arbitraria. Quest'ultimo non esiste più.
questo significa cambiamento da xrange
a range
è molto pari ad una variazione nome ma lavorare con valori arbitrari.
Ho verificato anche il codice byte disassemblato.
Di seguito si riporta il codice di byte smontato per la funzione foo()
:
Python 3.4:
---------------
13 0 LOAD_GLOBAL 0 (MAX_NUM)
3 STORE_FAST 0 (i)
14 6 SETUP_LOOP 26 (to 35)
>> 9 LOAD_FAST 0 (i)
12 LOAD_CONST 1 (0)
15 COMPARE_OP 4 (>)
18 POP_JUMP_IF_FALSE 34
15 21 LOAD_FAST 0 (i)
24 LOAD_CONST 2 (1)
27 INPLACE_SUBTRACT
28 STORE_FAST 0 (i)
31 JUMP_ABSOLUTE 9
>> 34 POP_BLOCK
>> 35 LOAD_CONST 0 (None)
38 RETURN_VALUE
python 2.7
-------------
13 0 LOAD_GLOBAL 0 (MAX_NUM)
3 STORE_FAST 0 (i)
14 6 SETUP_LOOP 26 (to 35)
>> 9 LOAD_FAST 0 (i)
12 LOAD_CONST 1 (0)
15 COMPARE_OP 4 (>)
18 POP_JUMP_IF_FALSE 34
15 21 LOAD_FAST 0 (i)
24 LOAD_CONST 2 (1)
27 INPLACE_SUBTRACT
28 STORE_FAST 0 (i)
31 JUMP_ABSOLUTE 9
>> 34 POP_BLOCK
>> 35 LOAD_CONST 0 (None)
38 RETURN_VALUE
E sotto è il codice di byte smontato per la funzione foo_for()
:
Python: 3.4
19 0 SETUP_LOOP 20 (to 23)
3 LOAD_GLOBAL 0 (xrange)
6 LOAD_GLOBAL 1 (MAX_NUM)
9 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
12 GET_ITER
>> 13 FOR_ITER 6 (to 22)
16 STORE_FAST 0 (i)
20 19 JUMP_ABSOLUTE 13
>> 22 POP_BLOCK
>> 23 LOAD_CONST 0 (None)
26 RETURN_VALUE
Python: 2.7
-------------
19 0 SETUP_LOOP 20 (to 23)
3 LOAD_GLOBAL 0 (xrange)
6 LOAD_GLOBAL 1 (MAX_NUM)
9 CALL_FUNCTION 1
12 GET_ITER
>> 13 FOR_ITER 6 (to 22)
16 STORE_FAST 0 (i)
20 19 JUMP_ABSOLUTE 13
>> 22 POP_BLOCK
>> 23 LOAD_CONST 0 (None)
26 RETURN_VALUE
Se confrontiamo entrambi i codici di byte hanno prodotto lo stesso codice byte disassemblato.
Ora mi chiedo quale cambiamento dal 2.7 al 3.4 stia davvero causando questo enorme cambiamento nei tempi di esecuzione nel dato pezzo di codice.
inserisci il codice completo e il metodo di misurazione – njzk2
L'esecuzione di questa operazione solo una volta con * l'intera configurazione dell'interprete * non ti dirà nulla. Usa 'timeit.timeit()' per eseguire invece le prove a tempo. –