Python Pyhton/Numpy与Fortran运行时间

Python Pyhton/Numpy与Fortran运行时间,python,numpy,fortran,Python,Numpy,Fortran,我有一个关于Numpy/Python和Fortran运行速度的问题。首先,我用Fortran重新编写了一个运行中的Python程序。它很好用。但我意识到,与Numpy数组相比,Fortran程序在更大的数组大小下速度越来越慢 这里有一些数字。对于低步长Fortan(使用英特尔Fortran编译器)需要0,2秒,Python需要5秒。第一次看到这个我非常高兴。但是后来我减小了步长,Fortran程序用了770秒,而python是1450秒。这几乎是损失的10倍。我想如果我进一步减小步长,Pytho

我有一个关于Numpy/Python和Fortran运行速度的问题。首先,我用Fortran重新编写了一个运行中的Python程序。它很好用。但我意识到,与Numpy数组相比,Fortran程序在更大的数组大小下速度越来越慢

这里有一些数字。对于低步长Fortan(使用英特尔Fortran编译器)需要0,2秒,Python需要5秒。第一次看到这个我非常高兴。但是后来我减小了步长,Fortran程序用了770秒,而python是1450秒。这几乎是损失的10倍。我想如果我进一步减小步长,Python将再次更快。那太糟糕了

我看了几乎所有的步骤。循环中的Fortran数组速度慢10倍(步长小10倍),这在某种程度上是合乎逻辑的。但numpy阵列的速度仅慢2-3倍

有人知道这些numpy函数做什么,它们不会线性地失去速度吗?在Fortran中有什么可比的吗

下面是一个简短的例子,但是整个代码有1000多个列,所以没有人会读这个。psi是一个复杂数组,r是一个实数组/双数组,其长度取决于Python代码

phi0= 4* pi * np.cumsum(np.cumsum(r * np.abs(chi)**2) * dr) * dr / r
phi0 += - phi0[-1] - N/r[-1]
dr=0.1时需要0.00006s,dr=0.01时需要0.00008s,dr=0.001时需要0.0002s

下面是fortran代码:

 integer :: i,j,m
double precision :: sum2_j, pi=3.14159265359, N, dr, sum1_i
double precision, dimension (:), allocatable ::  sum1_array, phi, step1, r
complex(8), dimension(:), allocatable :: psi
!double precision :: start, finish

m=size(psi)
allocate (phi(m))
allocate (sum1_array(m))
allocate (step1(m))

!call cpu_time(start)

sum1_i=0
step1=r*abs(psi)**2
do i=1,size(psi)
sum1_i=sum1_i+step1(i)
sum1_array(i)=sum1_i*dr
end do


sum2_j=0
do j=1,size(phi)
sum2_j=sum2_j + sum1_array(j)
phi(j)=4*pi*sum2_j*dr/r(j)
end do


phi=phi - phi(size(phi))-N/r(size(r))
使用eclipse/photran(英特尔fortran大约快2倍)的运行时: dr=0.1:0.0000008s,dr=0.01:0.00006s,dr=0.001:0.00045s

正如您所看到的,Python在较低的步长下几乎慢10倍,但在较高的步长下甚至更快。这个问题涉及fortran代码中的两个循环。这不是专门针对那个代码的。它发生在所有循环中。正如我所说,这只是一个例子。
到目前为止,没有什么我不能尝试的,因为我真的不明白为什么会发生这种情况。

也许我太累了,但为什么需要两个循环?两个循环都有相同的迭代次数,您只需要求和到该索引

!personally I would define the used precission the following way:   
!integer, parameter:: singlep = selected_real_kind(6,37)!Single
integer, parameter:: doublep = selected_real_kind(15,307)!Double

!real(kind=doublep) :: sum2_j, pi=3.14159265359_doublep, N, dr, sum1_i,pi4dr

integer :: i,j,sizepsi
double precision :: sum2_j, pi=3.14159265359, N, dr, sum1_i
double precision, dimension (:), allocatable ::  sum1_array, phi, step1, r
complex(8), dimension(:), allocatable :: psi
!double precision :: start, finish
pi4dr=4.0*dr*pi


sizepsi=size(psi)
allocate (phi(sizepsi))

!call cpu_time(start)

sum1_i=0.0!you shold add the precision here like 0.0_doublep
sum2_j=0.0

do i=1,sizepsi !we already know how large psi is
    sum1_i=sum1_i+r(i)*abs(psi(i))**2
    sum2_j=sum2_j + sum1_i*dr
    phi(i)=pi4dr*sum2_j/r(i)
end do

phi=phi - phi(sizepsi)-N/r(sizepsi) !size(phi)=size(r)=size(psi)
由于您的示例代码无法运行,因此我不打算对其进行测试并比较结果。
编辑:将内部循环更改为稍快的版本。

如果您的Fortran代码未分配
m=size(psi)
psi
的话,我不会相信它。可编译的MWE几乎总是从这里的专家那里获得具体建议的最快方法。我知道将代码拆分成几行可能会很麻烦,但这是值得的。@Fortran 1在这种情况下,请显示a。并为Fortran和Python显示它。照目前的情况,没有人能证实你的时间安排,也没有人能解释你的时间安排。其中一种可能是numpy是使用并行化(simd和openmp中的任意一种)编译的,而不是使用Fortran代码。编译器和编译选项是什么?numpy的版本是什么?那么谷歌错了——但更有可能的是,你错了。基本numpy包至少有,并调用了Intel MKL,后者也有openmp。谢谢,但令人惊讶的是,我认为它需要更多的时间来构建,或者至少不会更快。10次测量的平均值表示:使用您的代码(dr=0.01):5*10-5s,使用我的代码4*10-5s。正如其他人已经说过的,如果没有适当的MRE(以及使用的编译器选项),测试和给出有用的答案是很难的,也就是说我很无聊,所以我添加了代码来测试计时(使用gfortran-O2编译)。性能取决于psi的大小,对于较小的psi,谢谢,但我要计算的向量大小大约为1e5,我看不到运行时间的差异。