首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python/Numpy与Fortran运行时间

Python/Numpy与Fortran运行时间
EN

Stack Overflow用户
提问于 2021-01-22 01:27:19
回答 1查看 170关注 0票数 0

我有一个关于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代码。

代码语言:javascript
复制
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代码:

代码语言:javascript
复制
 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代码中的两个循环有关。它不是特定于该代码。它发生在所有循环中。正如我所说的,这只是一个例子。到目前为止,没有什么我不会尝试的,因为我不明白为什么会发生这种情况。

EN

回答 1

Stack Overflow用户

发布于 2021-01-22 08:32:22

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

代码语言:javascript
复制
!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)

由于您的示例代码不可运行,因此我将不对其进行测试和比较结果。编辑:将内循环更改为稍微快一点的版本。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65832645

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档