【发布时间】:2021-01-21 17:27:19
【问题描述】:
我有一个关于 Numpy /Python 和 Fortran 运行速度的问题。首先,我在 Fortran 中重新编写了一个正在运行的 Python 程序。它工作正常。但我意识到,与 Numpy 数组相比,使用更大的数组大小,Fortran 程序正在失去越来越多的速度。
这里有一些数字。对于低步长,Fortran(使用 Intel Fortran 编译器)需要 0.2 秒,而 Python 需要 5 秒。首先,当我看到这个时,我很高兴。但是后来我减小了步长,Fortran 程序用了 770 s,而 python 是 1450 s。这几乎是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(intel fortran 大约快 2 倍): dr=0.1: 0.0000008s, dr=0.01: 0.00006s, dr=0.001: 0.00045s
如您所见,Python 在较小的步长下几乎慢了 10 倍,但在较大的步长下甚至更快。此问题涉及 FORTRAN 代码中的两个循环。它并不特定于该代码。它发生在所有循环中。正如我所说,这只是一个例子。 到目前为止,没有什么我不会尝试的,因为我不明白为什么会发生这种情况。
【问题讨论】:
-
当你的 Fortran 代码有
m=size(psi)而psi未分配时,我不会信任它。 -
可编译的 MWE 几乎总是从这里的专家那里获得具体建议的最快方式。我知道将代码精简为几行会很麻烦,但值得付出努力。
-
@fortran1 在这种情况下,请显示minimal reproducible example。
-
并为 Fortran 和 Python 显示它。照原样,没有人可以确认您的时间或解释它们。其中一种可能性可能是 numpy 是通过并行化(simd 和 openmp 之一)而不是 Fortran 代码编译的。什么是编译器和编译选项? numpy 的版本是多少?