Python比c ++慢大约40倍

时间:2013-11-17 11:19:28

标签: c++ python performance

我正在实现滚动中值解决方案,并且不确定为什么我的python实现比c ++实现慢大约40倍。

以下是完整的实施

C ++

#include <iostream>
#include <vector>
#include <string.h>
using namespace std;

int tree[17][65536];

void insert(int x) { for (int i=0; i<17; i++) { tree[i][x]++; x/=2; } }
void erase(int x) { for (int i=0; i<17; i++) { tree[i][x]--; x/=2; } }
int kThElement(int k) {
    int a=0, b=16;
    while (b--) { a*=2; if (tree[b][a]<k) k-=tree[b][a++]; }
    return a;
}

long long sumOfMedians(int seed, int mul, int add, int N, int K) {
    long long result = 0;
    memset(tree, 0, sizeof(tree));
    vector<long long> temperatures;
    temperatures.push_back( seed );
    for (int i=1; i<N; i++)
      temperatures.push_back( ( temperatures.back()*mul+add ) % 65536 );
    for (int i=0; i<N; i++) {
      insert(temperatures[i]);
      if (i>=K) erase(temperatures[i-K]);
      if (i>=K-1) result += kThElement( (K+1)/2 );
    }
    return result;
}

// default input
// 47 5621 1 125000 1700
// output
// 4040137193

int main()
{   
  int seed,mul,add,N,K;
  cin >> seed >> mul >> add >> N >> K;
  cout << sumOfMedians(seed,mul,add,N,K)  << endl;
  return 0;
}

的Python

def insert(tree,levels,n):
        for i in xrange(levels):
                tree[i][n] += 1
                n /= 2
def delete(tree,levels,n):
        for i in xrange(levels):
                tree[i][n] -= 1
                n /= 2

def kthElem(tree,levels,k):
        a = 0
        for b in reversed(xrange(levels)):
                a *= 2
                if tree[b][a] < k:
                        k -= tree[b][a]
                        a += 1
        return a

def main():
        seed,mul,add,N,K = map(int,raw_input().split())
        levels = 17
        tree = [[0] * 65536 for _ in xrange(levels)]
        temps = [0] * N
        temps[0] = seed
        for i in xrange(1,N):
                temps[i] = (temps[i-1]*mul + add) % 65536
        result = 0
        for i in xrange(N):
                insert(tree,levels,temps[i])
                if (i >= K):
                        delete(tree,levels,temps[i-K])              
                if (i >= K-1):
                        result += kthElem(tree,levels,((K+1)/2))

        print result

# default input
# 47 5621 1 125000 1700
# output
# 4040137193
main()

在上面提到的输入中(在代码的注释中)C ++代码花了0.06 seconds而python花了2.3 seconds

有人可以提出我的python代码可能出现的问题,以及如何将性能提高到不到10倍?

我不希望它接近c ++实现,但是大约5-10x。我知道我可以通过使用像numpy(和/或scipy)这样的库来优化它。我从使用python解决编程挑战的角度来问这个问题。这些挑战中通常不允许使用这些库。我只想问是否有可能在python中击败这个算法的时间限制。

如果有人感兴趣,C ++代码是从http://community.topcoder.com/tc?module=Static&d1=match_editorials&d2=srm310

的浮动中位数问题借来的

[编辑]

对于那些认为使用numpy数组会改善性能的人来说,它并没有。另一方面,只使用numpy ndarray而不是列表列表,性能进一步降低到大约14秒,这比c ++慢了200倍。

2 个答案:

答案 0 :(得分:4)

正如您所发现的那样,计算绑定和程序编写的纯Python代码可能很慢。如果你想在Python中创建一些可以快速运行这样的任务的东西,你需要使用一些丰富的C(或C ++,Fortran或其他)扩展。例如,统计和数学人员使用NumPy和SciPy以及相关工具,这些工具易于从Python中使用,但实际上是用编译语言实现的,并且具有高性能(如果小心使用)。

如果您想尝试使用纯Python来提高性能,可以尝试使用“cProfile”模块来分析代码。但它可能无法接近C ++速度,除非您使用NumPy等更智能的模块或编写自己的扩展。

通过重构,您可能会获得少量收益:

reversed(xrange(levels))

特别是如果您使用的是Python 2.x,因为这将创建一个实际的列表。你可以这样做:

xrange(levels - 1, -1, -1)

答案 1 :(得分:2)

  

有人可以建议如何将性能提高到不到10倍?

  1. 描述代码。
  2. 使用NumPy而不是本机列表。
  3. 如果结果不够,请考虑使用Cython作为关键部分。