在将其转换为C ++之前,我一直在使用Python做一些快速原型设计,发现在某些情况下Python代码的运行速度明显快于C ++代码!
考虑用Python和C ++编写的这个简单循环:
python:
import numpy as np
import datetime
N = 16777216
f_s = 8000.0
t_s = 1/f_s
y = np.empty(N)
start = datetime.datetime.now()
for n in range(0,N):
y[n] = np.sin(2*np.pi*1000*n*t_s) + 0.5*np.sin(2*np.pi*2000*n*t_s + 3*np.pi/4)
stop = datetime.datetime.now()
duration = stop - start
print("duration ", duration.microseconds, " microseconds")
输出:
duration 842000 microseconds
C ++:
#include <chrono>
#include <cmath>
#include <iostream>
#include <vector>
int main() {
int N = 16777216;
int f_s = 8000;
double t_s = 1.0 / f_s;
std::vector<double> x(N);
auto start = std::chrono::high_resolution_clock::now();
for (int n = 0; n < N; ++n)
{
x[n] = std::sin(2 * M_PI * 1000 * n * t_s) + 0.5 * std::sin(2 * M_PI * 2000 * n * t_s + 3 * M_PI / 4);
}
auto stop = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
std::cout << "duration " << duration.count() << " microseconds." << std::endl;
}
输出:
duration 1993000 microseconds.
Python代码确实需要花费大量时间来启动,而C ++代码会立即运行。 (也许Python解释器在启动时做了一些需要很长时间的优化?)但即使抛开这个事实,一旦Python代码运行,循环本身在Python中运行得更快。
这让我感到非常惊讶,但我似乎无法弄清楚Python如何快速运行这个循环。我甚至尝试在不同的优化级别编译C ++代码,看看编译器是否只是在优化方面做得不好。上面的C ++示例是使用g++ -O3
编译的,以改进优化。当它没有削减它时,我甚至尝试了g++ -Ofast
,它将运行时间提高到1205000
微秒,但STILL显着慢于Python环路!
我试过谷歌搜索但我找不到任何真正的解释......怎么会发生这种情况?如何从C ++循环中获得更好的性能?如果不是更快,我希望我能像Python循环一样快地到达LEAST。
我正在运行Python 3.7.2
使用g++.exe (MinGW.org GCC-6.3.0-1) 6.3.0
和-O3
编译器开关编译C ++示例以改进优化。
我还尝试在linux环境中使用g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36)
编译C ++代码,结果类似。
您没有正确使用timedelta
的microseconds
组件。它只给出时间测量的sub-second微秒部分,而不是总经过的微秒。此代码突出显示您的错误
from datetime import datetime, timedelta
start = datetime(2019, 1, 1, 12, 0, 0, 0 )
end = datetime(2019, 1, 1, 12, 0, 1, microsecond=500000 )
diff = end - start
print('Total duration=',diff)
print('Total seconds=', diff.total_seconds())
print('microseconds=', diff.microseconds)
# output
Total duration= 0:00:01.500000
Total seconds= 1.5
microseconds= 500000
使用total_seconds
并乘以1e6,或者只需更改测试即可在几秒钟内报告结果。
注意C ++应该很容易赢得这个。您的循环具有固定数量的迭代,这些迭代在编译时是已知的,并且所有计算都不相互依赖。一个好的优化C ++编译器应该对该循环进行chunkify或部分展开,并使用SSE指令并行执行小型计算。