Pourquoi Python 3 est considérablement plus lent que Python 2? [dupliquer]
cette question a déjà une réponse ici:
j'ai essayé de comprendre pourquoi Python 3 prend en fait beaucoup de temps par rapport à Python 2 dans certaines situations, ci-dessous sont quelques cas J'ai vérifié de Python 3.4 à Python 2.7.
Note: J'ai passé en revue certaines des questions comme pourquoi n'y a-t-il pas de fonction xrange en Python3? et boucle en python3 beaucoup plus lent que python2 et même code plus lent en Python3 par rapport à Python2 , mais je pense que je n'ai pas eu la raison réelle derrière cette question.
j'ai essayé ce morceau de code pour montrer comment il est de faire la différence:
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
quand j'ai essayé de gérer ce programme avec py3.4 et py2.7 résultat.
Note: Ces statistiques proviennent d'une machine 64 bit
avec 2.6Ghz
processeur et calculé le temps en utilisant time.time()
en boucle simple.
Output : Python 3.4
-----------------
2.6392083168029785
0.9724123477935791
Output: Python 2.7
------------------
1.5131521225
0.475143909454
Je ne pense vraiment pas qu'il y ait eu des changements appliqués à while
ou xrange
de 2.7 à 3.4, je sais range
a commencé à jouer le rôle de xrange
dans py3.4 mais comme la documentation dit
range()
se comporte maintenant commexrange()
utilisé pour se comporter, sauf qu'il fonctionne avec des valeurs de taille arbitraire. Ce dernier n'existe plus.
cela signifie passer de xrange
à range
est très proche d'un changement de nom mais travailler avec des valeurs arbitraires.
j'ai vérifié le code byte démonté ainsi.
ci-dessous est le code octet démonté pour la fonction 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
et ci-dessous le code octet démonté pour la fonction 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
si nous comparons les deux codes octets, ils ont produit le même code octet démonté.
maintenant je me demande ce que le changement de 2.7 à 3.4 est réellement à l'origine de ce changement énorme dans le temps d'exécution dans la pièce Donnée de code.
1 réponses
la différence réside dans la mise en œuvre du type int
. Python 3.x utilise le type entier de taille arbitraire ( long
en 2.x) exclusivement, en Python 2.x pour les valeurs jusqu'à sys.maxint
un type plus simple int
est utilisé qui utilise un simple C long
sous la hotte.
une fois que vous limitez vos boucles à long
entiers, Python 3.x est plus rapide:
>>> from timeit import timeit
>>> MAX_NUM = 3*10**3
>>> def bar():
... i = MAX_NUM + sys.maxsize
... while i > sys.maxsize:
... i -= 1
...
Python 2:
>>> timeit(bar, number=10000)
5.704327821731567
Python 3:
>>> timeit(bar, number=10000)
3.7299320790334605
j'ai utilisé sys.maxsize
comme sys.maxint
a été supprimé de Python 3, mais la valeur entière est fondamentalement la même.
la différence de vitesse en Python 2 est donc limitée à la première (2 ** 63) - 1 nombre entier sur 64 bits, (2 ** 31)-1 nombre entier sur les systèmes 32 bits.
puisque vous ne pouvez pas utiliser le type long
avec xrange()
sur Python 2, Je n'ai pas inclus une comparaison de cette fonction.