我试图了解为什么我的一个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
答案 0 :(得分:5)
首先,python代码不会生成与fortran代码相同的输出。在fortran程序中,y是0到39的序列,接着是10个0,11个,......,一直到10个39。 python代码输出11个0,11个,一直到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),事情就会快得多......但这似乎不可能。