5

我在同一台机器上运行 python 2.7 和 matlab R2010a,什么都不做,它给了我 10 倍的速度

我上网查了一下,听说应该是同一个顺序。Python 将进一步减慢 for 循环中的 if 语句和数学运算符

我的问题:这是现实吗?还是有其他方法让它们以相同的速度顺序排列?


这是python代码

import time

start_time = time.time()

for r in xrange(1000):

      for c in xrange(1000):

         continue

elapsed_time = time.time() - start_time

print 'time cost = ',elapsed_time

Output: time cost = 0.0377440452576

这是matlab代码

tic

for i = 1:1000

    for j = 1:1000

    end

end

toc

Output: Escaped time is 0.004200 seconds

4

5 回答 5

9

发生这种情况的原因与JIT编译器有关,该编译器正在优化 MATLAB for 循环。feature accel off您可以使用和禁用/启用 JIT 加速器feature accel on。当您禁用加速器时,时间会发生巨大变化。

带有加速功能的 MATLAB:Elapsed time is 0.009407 seconds.

MATLAB 加速关闭:Elapsed time is 0.287955 seconds.

Python:time cost = 0.0511920452118

因此,JIT 加速器直接导致了您注意到的加速。您还应该考虑另一件事,这与您定义迭代索引的方式有关。在 MATLAB 和 python 两种情况下,您都使用迭代器来定义循环。在 MATLAB 中,您通过添加方括号 ( []) 创建实际值,而在 python 中,您使用range而不是xrange. 当您进行这些更改时

% MATLAB
for i = [1:1000]
    for j = [1:1000]

# python
for r in range(1000):
  for c in range(1000):

时代变成了

带有加速功能的 MATLAB:Elapsed time is 0.338701 seconds.

MATLAB 加速关闭:Elapsed time is 0.289220 seconds.

Python:time cost = 0.0606048107147

最后一个考虑因素是您是否要向循环添加快速计算。即t=t+1。那么时代就变成了

带有加速功能的 MATLAB:Elapsed time is 1.340830 seconds.

带加速关闭的 MATLAB:(Elapsed time is 0.905956 seconds.是的,关闭速度更快)

Python:time cost = 0.147221088409

我认为这里的寓意是,开箱即用的 for 循环的计算速度与极其简单的循环相当,具体取决于具体情况。但是,python 中还有其他可以显着加快速度的数值工具,到目前为止已经提出了 numpy 和 PyPy。

于 2013-06-21T19:29:46.737 回答
3

基本的 Python 实现,CPython,并不意味着超级快速。如果您需要高效的 matlab 式数值操作,请使用专为快速工作而设计的Pythonnumpy或实现,例如 PyPy 甚至 Cython。(用 C 编写 Python 扩展,当然会很快,也是一种可能的解决方案,但在这种情况下,您最好使用numpy并节省自己的精力。)

于 2013-06-21T19:32:58.967 回答
2

如果 Python 执行性能对你来说真的很重要,你可以看看PyPy

我做了你的测试:

import time
for a in range(10):
    start_time = time.time()
    for r in xrange(1000):
        for c in xrange(1000):
            continue

    elapsed_time = time.time()-start_time
    print elapsed_time

使用标准 Python 2.7.3,我得到:

0.0311839580536
0.0310959815979
0.0309510231018
0.0306520462036
0.0302460193634
0.0324130058289
0.0308878421783
0.0307397842407
0.0304911136627
0.0307500362396

而使用 PyPy 1.9.0(对应于 Python 2.7.2),我得到:

0.00921821594238
0.0115230083466
0.00851202011108
0.00808095932007
0.00496387481689
0.00499391555786
0.00508499145508
0.00618195533752
0.005126953125
0.00482988357544

PyPy 的加速确实令人惊叹,并且当其 JIT 编译器优化超过其成本时,它确实变得显而易见。这也是我引入额外 for 循环的原因。对于这个例子,绝对不需要修改代码。

于 2013-06-21T19:23:57.497 回答
0

这只是我的看法,但我认为这个过程有点复杂。基本上,Matlab 是 C 的优化层,因此通过适当的矩阵初始化和函数调用的最小化(避免在 Matlab 中使用“.”类似对象的运算符),您将获得截然不同的结果。考虑以下具有余弦函数的波发生器的简单示例。Matlab 时间 = 实际调试会话中的 0.15 秒,Python 时间 = 实际调试会话 (Spyder) 中的 25 秒,因此 Python 变慢了 166 倍。由 Python 3.7.4 直接运行。机器时间大约为 5 秒,所以仍然是不可忽略的 33 倍。

MATLAB:

AW(1,:) = [800 , 0    ]; % [amp frec]
AW(2,:) = [300 , 4E-07]; 
AW(3,:) = [200 , 1E-06];
AW(4,:) = [ 50 , 4E-06];
AW(5,:) = [ 30 , 9E-06];
AW(6,:) = [ 20 , 3E-05];
AW(7,:) = [ 10 , 4E-05];
AW(8,:) = [  9 , 5E-04];
AW(9,:) = [  7 , 7E-04];
AW(10,:)= [  5 , 8E-03];

phas    = 0

tini    = -2*365 *86400; % 2 years backwards in seconds
dt      = 200;        % step, 200 seconds
tfin    = 0;          % present
vec_t   = ( tini: dt: tfin)'; % vector_time

nt      = length(vec_t);
vec_t   = vec_t - phas;
wave    = zeros(nt,1);

for it = 1:nt
    suma = 0;
    t    = vec_t(it,1);
    for iW = 1:size(AW,1)
        suma = suma + AW(iW,1)*cos(AW(iW,2)*t);
    end
    wave(it,1) = suma;
end

PYTHON:

import numpy as np

AW      = np.zeros((10,2))
AW[0,:] = [800 , 0.0]
AW[1,:] = [300 , 4E-07]; # [amp frec]
AW[2,:] = [200 , 1E-06];
AW[3,:] = [ 50 , 4E-06];
AW[4,:] = [ 30 , 9E-06];
AW[5,:] = [ 20 , 3E-05];
AW[6,:] = [ 10 , 4E-05];
AW[7,:] = [  9 , 5E-04];
AW[8,:] = [  7 , 7E-04];
AW[9,:] = [  5 , 8E-03];

phas    = 0

tini    = -2*365 *86400 # 2 years backwards
dt      = 200
tfin    = 0           # present
nt      = round((tfin-tini)/dt) + 1 
vec_t   = np.linspace(tini,tfin1,nt) - phas

wave    = np.zeros((nt))

for it in range(nt):
    suma   = 0
    t      = vec_t[fil]
    for iW in range(np.size(AW,0)):
        suma = suma + AW[iW,0]*np.cos(AW[iW,1]*t)
    #endfor iW
    wave[it] = suma
#endfor it

为了在 Python 中处理这些方面,我建议直接编译成可执行文件以二进制可能危及项目的数字部分(或者例如 C 或 Fortran 成可执行文件,然后由 Python 调用)。当然,其他建议表示赞赏。

于 2019-08-13T16:00:42.400 回答
0

我使用 MATLAB 和 Python 中的相同(改编)代码测试了 FIR 滤波器,包括频率扫描。FIR 滤波器非常大,N = 100 阶,我在两个代码下方发布,但将时序结果留在这里:

MATLAB:经过的时间是 11.149704 秒。

Python:时间成本 = 247.8841781616211 秒。

Python 慢了 25 倍!

MATLAB 代码(主要):

f1 = 4000; % bandpass frequency (response = 1).
f2 = 4200; % bandreject frequency (response = 0).
N = 100;   % FIR filter order.
k = 0:2*N;
fs = 44100; Ts = 1/fs; % Sampling freq. and time.

% FIR Filter numerator coefficients:
Nz = Ts*(f1+f2)*sinc((f2-f1)*Ts*(k-N)).*sinc((f2+f1)*Ts*(k-N));
f = 0:fs/2;
w = 2*pi*f;
z = exp(-i*w*Ts);

% Calculation of the expected response:
Hz = polyval(Nz,z).*z.^(-2*N);
figure(1)
plot(f,abs(Hz))
title('Gráfica Respuesta Filtro FIR (Filter Expected Response)') 
xlabel('frecuencia f (Hz)') 
ylabel('|H(f)|') 
xlim([0, 5000])
grid on

% Sweep Frequency Test:

tic
% Start and Stop frequencies of sweep, t = tmax = 50 seconds = 5000 Hz frequency:

fmin = 1; fmax = 5000; tmax = 50; 
t = 0:Ts:tmax;
phase = 2*pi*fmin*t + 2*pi*((fmax-fmin).*t.^2)/(2*tmax);
x = cos(phase);

y = filtro2(Nz, 1, x); % custom filter function, not using "filter" library here.

figure(2)
plot(t,y)
title('Gráfica Barrido en Frecuencia Filtro FIR (Freq. Sweep)') 
xlabel('Tiempo Barrido: t = 10 seg = 1000 Hz') 
ylabel('y(t)') 
xlim([0, 50])
grid on
toc

MATLAB 自定义过滤器功能

function y = filtro2(Nz, Dz, x)

Nn = length(Nz);
Nd = length(Dz);


N = length(x);
Nm = max(Nn,Nd);


x1 = [zeros(Nm-1,1) ; x'];
y1 = zeros(Nm-1,1);
for n = Nm:N+Nm-1
    y1(n) = Nz(Nn:-1:1)*x1(n-Nn+1:n)/Dz(1);
    if Nd > 1
        y1(n) = y1(n) - Dz(Nd:-1:2)*y1(n-Nd+1:n-1)/Dz(1);
    end
end
y = y1(Nm:Nm+N-1);
end

Python代码(主要):

import numpy as np
from matplotlib import pyplot as plt
import FiltroDigital as fd
import time

j = np.array([1j])
pi = np.pi

f1, f2 = 4000, 4200
N = 100
k = np.array(range(0,2*N+1),dtype='int')
fs = 44100; Ts = 1/fs;
Nz = Ts*(f1+f2)*np.sinc((f2-f1)*Ts*(k-N))*np.sinc((f2+f1)*Ts*(k-N));
f = np.arange(0, fs/2, 1)
w = 2*pi*f
z = np.exp(-j*w*Ts)
Hz = np.polyval(Nz,z)*z**(-2*N)
plt.figure(1)
plt.plot(f,abs(Hz))
plt.title("Gráfica Respuesta Filtro FIR") 
plt.xlabel("frecuencia f (Hz)") 
plt.ylabel("|H(f)|") 
plt.xlim(0, 5000)
plt.grid()
plt.show()


start_time = time.time()
fmin = 1; fmax = 5000; tmax = 50;
t = np.arange(0, tmax, Ts)
fase = 2*pi*fmin*t + 2*pi*((fmax-fmin)*t**2)/(2*tmax)
x = np.cos(fase)
y = fd.filtro(Nz, [1], x)
plt.figure(2)
plt.plot(t,y)
plt.title("Gráfica Barrido en Frecuencia Filtro FIR") 
plt.xlabel("Tiempo Barrido: t = 10 seg = 1000 Hz") 
plt.ylabel("y(t)") 
plt.xlim(0, 50)
plt.grid()
plt.show()
elapsed_time = time.time() - start_time
print('time cost = ', elapsed_time)

Python自定义过滤器功能

import numpy as np

def filtro(Nz, Dz, x):

    Nn = len(Nz); 
    Nd = len(Dz);
    Nz = np.array(Nz,dtype=float)
    Dz = np.array(Dz,dtype=float)
    x = np.array(x,dtype=float)


    N = len(x);
    Nm = max(Nn,Nd);
    
    x1 = np.insert(x, 0, np.zeros((Nm-1,), dtype=float))
    y1 = np.zeros((N+Nm-1,), dtype=float)              

     for n in range(Nm-1,N+Nm-1) :
        y1[n] = sum(Nz*np.flip( x1[n-Nn+1:n+1]))/Dz[0]   # = y1FIR[n]
        if Nd > 1:
            y1[n] = y1[n] - sum(Dz[1:]*np.flip( y1[n-Nd+1:n]))/Dz[0]
            print(y1[n])

    y = y1[Nm-1:]
    return y
于 2021-10-29T00:49:17.077 回答