python – 如何在这个短代码中提高numpy性能?

我试图了解为什么我的一个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),事情会快得多……但这似乎不可能.

上一篇:linux – FORTRAN内存利用率 – 静态与动态


下一篇:linux – 如何使用fortran或shell在同一文件中突出显示其右侧的不匹配数据?