我试图了解为什么我的一个python脚本比gfortran慢了约4倍,我必须这样做:
import numpy as np
nvar_x=40
nvar_y=10
def fn_tst(x):
for i in range(int(1e7)):
y=np.repeat(x,1+nvar_y)
return y
x = np.arange(40)
y = fn_tst(x)
print y.min(),y.max()
这比以下fortran代码慢大约13倍
module test
integer,parameter::nvar_x=40,nvar_y=10
contains
subroutine fn_tst(x,y)
real,dimension(nvar_x)::x
real,dimension(nvar_x*(1+nvar_y))::y
do i = 1,10000000
do k = 1,nvar_x
y(k)=x(k)
ibeg=nvar_x+(k-1)*nvar_y+1
iend=ibeg+nvar_y-1
y(ibeg:iend)=x(k)
enddo
enddo
end subroutine fn_tst
end module test
program tst_cp
use test
real,dimension(nvar_x)::x
real,dimension(nvar_x*(1+nvar_y))::y
do k = 1,nvar_x
x(k)=k-1
enddo
call fn_tst(x,y)
print *,minval(y),maxval(y)
stop
end
你能否提出加速python脚本的方法.其他指向numpy良好性能的指针将不胜感激.我宁愿坚持使用python而不是为fortran例程构建python包装器.
谢谢
@isedev,是的,就是这样. 1.2s gfortran与6.3s for Python?这是我第一次担心性能,但正如我所说,在我试图加速的代码中,我只能使用Python获得大约四分之一的速度.
对,抱歉代码没有做同样的事情.实际上,您在循环中指示的内容更像我在原始代码中所拥有的内容.
除非我遗漏了什么,否则我不同意最后的陈述:我必须在fn_tst中创建y.和np.repeat只是RHS上的一个术语(将o / p直接放在现有数组中).如果我注释掉np.repeat术语的话很快……
rhs_slow = rhs[:J]
rhs_fast = rhs[J:]
rhs_fast[:] = c* ( b*in2[3:-1] * ( in2[1:-3] - in2[4:] ) - fast) + hc_ovr_b * np.repeat(slow,K) #slow
解决方法:
首先,python代码不会生成与fortran代码相同的输出.在fortran程序中,y是0到39的序列,接着是10个0,11个,……,一直到10个39. python代码输出11个0,11个1一直到11个39.
此代码生成相同的输出并执行与原始代码类似数量的内存分配:
import numpy as np
nvar_x = 40
nvar_y = 10
def fn_tst(x):
for i in range(10000000):
y = np.empty(nvar_x*(1+nvar_y))
y[0:nvar_x] = x[0:nvar_x]
y[nvar_x:] = np.repeat(x,nvar_y)
return y
x = np.arange(40)
fn_tst(x)
print y.min(), y.max()
在我的系统上(仅限1,000,000个循环),fortran代码在1.2s内运行,上面的python在8.6s内运行.
但是,这不是一个公平的比较:使用fortran代码,y被分配一次(在fn_tst例程之外)并且使用python代码,y在fn_tst函数内分配.
因此,如下重写Python代码可提供更好的比较:
import numpy as np
nvar_x = 40
nvar_y = 10
def fn_tst(x,y):
for i in range(10000000):
y[0:nvar_x] = x[0:nvar_x]
y[nvar_x:] = np.repeat(x,nvar_y)
return y
x = np.arange(40)
y = np.empty(nvar_x*(1+nvar_y))
fn_tst(x,y)
print y.min(), y.max()
在我的系统上,上面运行在6.3s(再次,1,000,000次迭代).所以已经约快了25%.
在这种情况下,主要的性能是numpy.repeat()生成一个数组,然后需要将其复制回y.如果可以指示numpy.repeat()将其输出直接放在现有数组中(即在这种情况下为y),事情会快得多……但这似乎不可能.