我觉得这个问题很有趣,因为每次我遇到类似 NumPy 速度(与 C/C++ 相比)的话题时,总会有答案说“它只是一个薄薄的包装层,其核心是用 C 编写的,所以它很快”,但这并不能解释为什么带有额外层(即使是薄的一层)的 C 应该比 C 更慢。
答案是:当正确编译时,你的 C++ 代码不会比你的 Python 代码慢。
我做了一些基准测试,起初 NumPy 似乎更快。但我忘记了使用GCC优化编译。
我重新计算了所有内容,并将结果与你的代码的纯 C++ 版本进行了比较。 我正在使用 GCC 版本4.9.2 和Python 2.7.9(使用相同的 GCC 从源代码编译)。 编译你的 C++ 代码时,我使用了g++ -O3 main.cpp -o main
,编译我的 C 代码时,我使用了gcc -O3 main.c -lm -o main
。 在所有示例中,我使用一些数字(0.1、0.4)填充了data
变量,因为它会改变结果。 我也将 np.arrays 更改为使用双精度浮点数 (dtype=np.float64
),因为 C++ 示例中有双精度浮点数。我的纯 C 代码版本(类似于你的代码):
#include <math.h>
#include <stdio.h>
#include <time.h>
const int k_max = 100000;
const int N = 10000;
int main(void)
{
clock_t t_start, t_end;
double data1[N], data2[N], coefs1[k_max], coefs2[k_max], seconds;
int z;
for( z = 0; z < N; z++ )
{
data1[z] = 0.1;
data2[z] = 0.4;
}
int i, j;
t_start = clock();
for( i = 0; i < k_max; i++ )
{
for( j = 0; j < N-1; j++ )
{
coefs1[i] += data2[j] * (cos((i+1) * data1[j]) - cos((i+1) * data1[j+1]));
coefs2[i] += data2[j] * (sin((i+1) * data1[j]) - sin((i+1) * data1[j+1]));
}
}
t_end = clock();
seconds = (double)(t_end - t_start) / CLOCKS_PER_SEC;
printf("Time: %f s\n", seconds);
return coefs1[0];
}
对于k_max=100000,N=10000
的结果如下:
- Python 70.284362 s
- C++ 69.133199 s
- C 61.638186 s
Python和C++的时间基本相同,但请注意Python有一个长度为k_max
的循环,应该比C/C++的循环慢得多。确实如此。
对于k_max=1000000,N=1000
,我们有:
- Python 115.42766 s
- C++ 70.781380 s
对于k_max=1000000,N=100
:
- Python 52.86826 s
- C++ 7.050597 s
因此,差异随着k_max/N
的分数而增加,但即使是N
比k_max
大得多,例如k_max=100,N=100000
,Python也不会更快:
- Python 0.651587 s
- C++ 0.568518 s
显然,C/C++和Python之间的主要速度差异在于for
循环。但我想找出NumPy中数组上简单操作与C中数组操作之间的差异。在代码中使用NumPy的优点包括:1. 用一个数乘以整个数组,2. 计算整个数组的sin/cos,3. 对数组的所有元素求和,而不是对每个单独项目进行这些操作。因此,我准备了两个脚本来仅比较这些操作。
Python脚本:
import numpy as np
from time import time
N = 10000
x_len = 100000
def main():
x = np.ones(x_len, dtype=np.float64) * 1.2345
start = time()
for i in xrange(N):
y1 = np.cos(x, dtype=np.float64)
end = time()
print('cos: {} s'.format(end-start))
start = time()
for i in xrange(N):
y2 = x * 7.9463
end = time()
print('multi: {} s'.format(end-start))
start = time()
for i in xrange(N):
res = np.sum(x, dtype=np.float64)
end = time()
print('sum: {} s'.format(end-start))
return y1, y2, res
if __name__ == '__main__':
main()
C脚本:
#include <math.h>
#include <stdio.h>
#include <time.h>
const int N = 10000;
const int x_len = 100000;
int main()
{
clock_t t_start, t_end;
double x[x_len], y1[x_len], y2[x_len], res, time;
int i, j;
for( i = 0; i < x_len; i++ )
{
x[i] = 1.2345;
}
t_start = clock();
for( j = 0; j < N; j++ )
{
for( i = 0; i < x_len; i++ )
{
y1[i] = cos(x[i]);
}
}
t_end = clock();
time = (double)(t_end - t_start) / CLOCKS_PER_SEC;
printf("cos: %f s\n", time);
t_start = clock();
for( j = 0; j < N; j++ )
{
for( i = 0; i < x_len; i++ )
{
y2[i] = x[i] * 7.9463;
}
}
t_end = clock();
time = (double)(t_end - t_start) / CLOCKS_PER_SEC;
printf("multi: %f s\n", time);
t_start = clock();
for( j = 0; j < N; j++ )
{
res = 0.0;
for( i = 0; i < x_len; i++ )
{
res += x[i];
}
}
t_end = clock();
time = (double)(t_end - t_start) / CLOCKS_PER_SEC;
printf("sum: %f s\n", time);
return y1[0], y2[0], res;
}
Python结果:
- 余弦:22.7199969292 秒
- 乘法:0.841291189194 秒
- 求和:1.15971088409 秒
C结果:
- 余弦:20.910590 秒
- 乘法:0.633281 秒
- 求和:1.153001 秒
正如您所看到的,NumPy非常快,但始终比纯C慢一些。
Time: 1 sekund
。你有没有碰巧以调试模式运行C++代码? - Bo Persson