2013-03-27 80 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