我有一个关于Numpy /Python和Fortran运行速度的问题。首先,我用Fortran重新编写了一个正在运行的Python程序。它工作得很好。但我意识到,Fortran程序在处理比Numpy数组更大的数组时,速度越来越慢。
以下是一些数字。对于步长较小的Fortran (使用英特尔Fortran编译器)需要0,2s,而Python需要5秒。首先,当我看到这一点时,我很高兴。但是后来我减小了步长,Fortran程序用了770秒,而python程序只用了1450秒,几乎损失了10倍。我想如果我进一步减小步长,Python会再次变得更快。这太糟糕了。
我看了几乎所有的步骤。循环中的Fortran数组慢10倍(步长小10倍),这在某种程度上是合乎逻辑的。但是numpy数组的速度只慢2-3倍。
有没有人知道这些numpy函数是做什么的,它们不会线性减速?在Fortran中有可比的功能吗?
这里有一个简短的例子,但是整个代码有超过1000列,所以没有人会读到这篇文章。psi是一个复数组,r是一个实数/双精度数组,其长度取决于dr。首先是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代码中的两个循环有关。它不是特定于该代码。它发生在所有循环中。正如我所说的,这只是一个例子。到目前为止,没有什么我不会尝试的,因为我不明白为什么会发生这种情况。
发布于 2021-01-22 08:32:22
也许我太累了,但是为什么你需要两个循环呢?两个循环都有相同的迭代次数,你只需要求和到那个索引...
!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)由于您的示例代码不可运行,因此我将不对其进行测试和比较结果。编辑:将内循环更改为稍微快一点的版本。
https://stackoverflow.com/questions/65832645
复制相似问题