2015-07-21 149 views
31

我一直在試圖理解爲什麼Python 3在某些情況下實際上比Python 2花費了很多時間,下面是我已經從python 3.4驗證到python 2.7的一些情況。爲什麼Python 3比Python 2慢得多?

注意:我已經通過了Why is there no xrange function in Python3?loop in python3 much slower than python2Same code slower in Python3 as compared to Python2等一些問題,但我覺得我沒有得到這個問題背後的實際原因。

我已經試過這一段代碼來顯示它是如何做的區別:

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 

當我試圖運行與py3.4和py2.7這個節目,我已經得到了以下 結果。

注意:這些統計信息是通過64 bit機器和2.6Ghz處理器計算出來的,並使用time.time()單循環計算出時間。

Output : Python 3.4 
----------------- 
2.6392083168029785 
0.9724123477935791 

Output: Python 2.7 
------------------ 
1.5131521225 
0.475143909454 

我真的不認爲出現了2.7應用於whilexrange到3.4的變化,我知道range已經開始充當在py3.4 xrange但文件說,

range()現在的行爲與xrange()相似,只是它可以處理任意大小的值。後者不再存在。

這意味着從xrange更改爲range非常類似於名稱更改,但使用任意值。

我已驗證反彙編的字節碼。

下面是功能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   

而且下面是功能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   

如果我們比較這兩個字節的代碼,他們已經生產相同的反彙編字節碼。

現在我想知道從2.7到3.4的變化是否真的會導致給定代碼片段執行時間的巨大變化。

+1

發佈全部代碼和測量方法 – njzk2

+3

只用一次*整個解釋器設置*就不會告訴你任何東西。使用'timeit.timeit()'來代替運行時間測試。 –

回答

26

不同之處在於執行int類型。 Python 3.x專門使用任意大小的整數類型(2.x中的long),而在Python 2.x中,值最大爲sys.maxint時,使用簡單的int類型,它使用簡單的C long

一旦你限制你的循環爲long整數,Python 3。x是更快:

>>> 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 

我用sys.maxsize作爲sys.maxint從Python 3的下降,但整數值基本相同。

Python 2中的速度差異因此限制在32位系統上的64位(2 ** 31) - 1整數上的第一個(2 ** 63) - 1整數。

由於您不能在Python 2上使用long類型和xrange(),所以我沒有包含該函數的比較。

+7

是否有任何理由不希望爲2 ** 63以下的整數進行優化?他們似乎是最常用的... – thebjorn

+0

@thebjorn:簡化使用一個'int'類型更重要。另外,如果你在這個大範圍內執行'for'循環,你可能會做一些錯誤的事情*無論如何*。 –

+4

但是,這種選擇是否使得例如數組索引等也比較慢?似乎其他語言(Smalltalk,Lisp,Haskell,Java)爲了優化整數的裝箱/拆箱而花費了一些時間,這些優化在像Python這樣的語言中是多餘的? – thebjorn

相關問題