2013-03-27 99 views
2

我正在考慮用python代碼替換一些C代碼並使用pypy作爲解釋器。代碼做了很多列表/字典操作。因此,爲了弄清楚pypy vs C的性能,我正在編寫排序算法。爲了測試我所有的讀取函數,我使用python和C++編寫了一個冒泡排序。 CPython當然是6.468s,pypy是0.366s,C++是0.229s。然後我想起我已經忘記了-O3的C++代碼,時間到了0.042s。對於32768數據集,-O3的C++只有2.588s,pypy是19.65s。有什麼我可以做,以加快我的Python代碼(除了使用更好的排序算法,當然)或我怎麼使用pypy(一些標誌或什麼)?Pypy(Python)優化

Python代碼(省略read_nums模塊,因爲它的時間是微不足道的:0.036s上32768數據集):

import read_nums 
import sys 

nums = read_nums.read_nums(sys.argv[1]) 

done = False 

while not done: 
    done = True 

    for i in range(len(nums)-1): 
     if nums[i] > nums[i+1]: 
      nums[i], nums[i+1] = nums[i+1], nums[i] 
      done = False 

$ time pypy-c2.0 bubble_sort.py test_32768_1.nums 
real 0m20.199s 
user 0m20.189s 
sys  0m0.009s 

C代碼(read_nums函數再次省略,因爲它需要很少的時間:0.017s):

#include <iostream> 
#include "read_nums.h" 

int main(int argc, char** argv) 
{ 
    std::vector<int> nums; 
    int count, i, tmp; 
    bool done; 

    if(argc < 2) 
    { 
     std::cout << "Usage: " << argv[0] << " filename" << std::endl; 
     return 1; 
    } 

    count = read_nums(argv[1], nums); 

    done = false; 

    while(!done) 
    { 
     done = true; 

     for(i=0; i<count-1; ++i) 
     { 
      if(nums[i] > nums[i+1]) 
      { 
       tmp = nums[i]; 
       nums[i] = nums[i+1]; 
       nums[i+1] = tmp; 
       done = false; 
      } 
     } 
    } 

    for(i=0; i<count; ++i) 
    { 
     std::cout << nums[i] << ", "; 
    } 

    return 0; 
} 

$ time ./bubble_sort test_32768_1.nums > /dev/null 
real 0m2.587s 
user 0m2.586s 
sys  0m0.001s 

PS第一段中給出的一些數字與時間的數字有些不同,因爲它們是我第一次得到的數字。

進一步的改進:

  • 剛試過的xrange而不是範圍和運行時間去16.370s。
  • 將代碼從第一個done = False開始移動到最後的done = False,速度現在是8.771-8.834s。
+0

如果使用像c代碼中那樣的tmp變量會發生什麼? – Claudiu 2013-03-27 17:59:36

+0

W/xrange需要19.431s,w/xrange和tmp需要19.760s。不知道爲什麼我的xrange剛剛退步。 – CrazyCasta 2013-03-27 18:23:10

+0

好吧,xrange no tmp顯然是一個異常值,我跑了5次,它的範圍是16.385s-17.158s。 tmp變量爲5次,範圍從18.923s-19.444s。 – CrazyCasta 2013-03-27 18:29:43

回答

3

回答這個問題最相關的方法是注意C,CPython和PyPy的速度沒有一個常數因子的不同:它最重要的取決於做什麼和它的寫法。例如,如果你的C代碼在「等價」的Python代碼自然使用字典的時候做了一些幼稚的事情,比如行走數組,那麼Python的任何實現都比C提供的更快,只要數組足夠長。當然,大多數現實生活中的例子並非如此,但同樣的觀點仍然適用於較小的範圍。沒有一種萬能的方式來預測用C編寫的程序的相對速度,或者用Python重寫並在CPython或PyPy上運行。

很明顯,有關於這些相對速度的指導原則:在小算法示例中,您可以預期PyPy的速度將接近「gcc -O0」的速度。在你的例子中,它「僅」慢了1.6倍。我們可能會幫助您優化它,或者甚至在PyPy中找到缺失的優化,以便獲得更多10%或30%的速度。但這是一個與你的真實程序無關的小例子。出於上述原因,我們在這裏獲得的速度與您最終獲得的速度只有模糊的關係。

爲了清晰起見,我只能說從C到Python的代碼重寫,特別是當C爲了進一步發展而變得過於糾結時,顯然是長期的勝利---即使在最後你需要用C重寫它的某些部分。 PyPy的目標是減少對此的需求。雖然很高興地說沒有人再需要C了,但這只是不正確:-)

+0

有兩件事:一,我想學習優化PyPy的技巧(比如使用函數而不是全局做東西),二,顯然我應該在C中使用正確的數據結構,但是例如,PyPy的實現字典可能非常好,爲了獲得類似的速度,它可能需要花費很多努力,在這種情況下PyPy會有優勢。 – CrazyCasta 2013-03-28 18:52:30