【发布时间】:2013-04-25 09:00:27
【问题描述】:
我的 Python 程序太慢了。因此,我对其进行了概要分析,发现大部分时间都花在了一个计算两点之间距离的函数上(一个点是 3 个 Python 浮点数的列表):
def get_dist(pt0, pt1):
val = 0
for i in range(3):
val += (pt0[i] - pt1[i]) ** 2
val = math.sqrt(val)
return val
为了分析这个函数为什么这么慢,我编写了两个测试程序:一个用 Python 编写,一个用 C++ 编写,它们执行类似的计算。他们计算 100 万对点之间的距离。 (下面是Python和C++的测试代码。)
Python 计算需要 2 秒,而 C++ 需要 0.02 秒。 100 倍的差异!
对于如此简单的数学计算,为什么 Python 代码比 C++ 代码慢得多?如何加快速度以匹配 C++ 性能?
用于测试的 Python 代码:
import math, random, time
num = 1000000
# Generate random points and numbers
pt_list = []
rand_list = []
for i in range(num):
pt = []
for j in range(3):
pt.append(random.random())
pt_list.append(pt)
rand_list.append(random.randint(0, num - 1))
# Compute
beg_time = time.clock()
dist = 0
for i in range(num):
pt0 = pt_list[i]
ri = rand_list[i]
pt1 = pt_list[ri]
val = 0
for j in range(3):
val += (pt0[j] - pt1[j]) ** 2
val = math.sqrt(val)
dist += val
end_time = time.clock()
elap_time = (end_time - beg_time)
print elap_time
print dist
用于测试的 C++ 代码:
#include <cstdlib>
#include <iostream>
#include <ctime>
#include <cmath>
struct Point
{
double v[3];
};
int num = 1000000;
int main()
{
// Allocate memory
Point** pt_list = new Point*[num];
int* rand_list = new int[num];
// Generate random points and numbers
for ( int i = 0; i < num; ++i )
{
Point* pt = new Point;
for ( int j = 0; j < 3; ++j )
{
const double r = (double) rand() / (double) RAND_MAX;
pt->v[j] = r;
}
pt_list[i] = pt;
rand_list[i] = rand() % num;
}
// Compute
clock_t beg_time = clock();
double dist = 0;
for ( int i = 0; i < num; ++i )
{
const Point* pt0 = pt_list[i];
int r = rand_list[i];
const Point* pt1 = pt_list[r];
double val = 0;
for ( int j = 0; j < 3; ++j )
{
const double d = pt0->v[j] - pt1->v[j];
val += ( d * d );
}
val = sqrt(val);
dist += val;
}
clock_t end_time = clock();
double sec_time = (end_time - beg_time) / (double) CLOCKS_PER_SEC;
std::cout << sec_time << std::endl;
std::cout << dist << std::endl;
return 0;
}
【问题讨论】:
-
因为编译代码总是会击败字节码解释的动态语言?使用
numpy跨如此大的数据集进行计算。 -
不是您的问题的答案,但是,您是否考虑过使用 numpy?
-
@Ashwin:您在这里并没有完全使用 Python 的优势,您的代码也不是最有效的。使用局部作用域与全局作用域会有所不同,展开循环并避免属性取消引用也会有所帮助。
-
您也可以尝试使用 pypy 运行此代码。编辑:对我来说 pypy 比 cpython 快 6.5 倍
-
在比较 C 和 CPython 时,特别希望“简单数学计算”有 100 倍的差异。如果一个模块在不使用 numpy 的情况下产生数百万个 3D 点;编写一个包装器来获取 numpy 数组。如果您将循环保留在纯 Python 中,Cython 不会帮助您实现 C 性能(与
for i in xrange(num)开销相比,在 Cython 中实现的get_dist()几乎是瞬时的(在我的机器上 num=1000000 为 14 毫秒))。 Cython 与 numpy 数组的互操作性非常好。如果您不能将计算表达为向量化的 numpy 操作,则可以使用 Cython。
标签: python performance