Python 很难让OpenMP与f2py一起工作
我正在为我的研究做一些模拟工作,在将fortran导入python脚本时遇到了一个障碍。作为背景,我使用Python已经有几年了,只是在需要的时候才在Fortran内部玩过 我在过去做过一些工作,用Fortran实现了一些简单的OpenMP功能。我不是这方面的专家,但我以前已经掌握了基本知识 我现在使用f2py创建一个库,我可以从python脚本中调用它。当我尝试编译openmp时,它会正确编译并运行到完成,但速度没有任何提高,从顶部看,CPU使用情况表明只有一个线程在运行 我已经在文档中搜索了f2py(它没有很好的文档),也做了正常的web搜索来寻找答案。我已经包括了我正在编译的Fortran代码以及一个调用它的简单python脚本。我还使用了compile命令 目前,我将模拟减少到10^4作为一个很好的基准。在我的系统上,运行需要3秒钟。最终我需要运行一些10^6的粒子模拟,所以我需要把时间缩短一点 如果有人能告诉我如何让我的代码正常工作,我将不胜感激。我还可以根据需要尝试包含有关系统的任何详细信息 干杯, 里尔坎Python 很难让OpenMP与f2py一起工作,python,fortran,fortran90,gfortran,f2py,Python,Fortran,Fortran90,Gfortran,F2py,我正在为我的研究做一些模拟工作,在将fortran导入python脚本时遇到了一个障碍。作为背景,我使用Python已经有几年了,只是在需要的时候才在Fortran内部玩过 我在过去做过一些工作,用Fortran实现了一些简单的OpenMP功能。我不是这方面的专家,但我以前已经掌握了基本知识 我现在使用f2py创建一个库,我可以从python脚本中调用它。当我尝试编译openmp时,它会正确编译并运行到完成,但速度没有任何提高,从顶部看,CPU使用情况表明只有一个线程在运行 我已经在文档中搜索了
1) 编撰
2) 要调用的Python脚本
import numpy as N
import calc_accel_jerk
# a is a (1e5,7) array with M,r,v information
a = N.load('../test.npy')
a = a[:1e4]
out = calc_accel_jerk.calc(a,a.shape[0])
print out[:10]
3) Fortran代码
subroutine calc (input_array, nrow, output_array)
implicit none
!f2py threadsafe
include "omp_lib.h"
integer, intent(in) :: nrow
double precision, dimension(nrow,7), intent(in) :: input_array
double precision, dimension(nrow,2), intent(out) :: output_array
! Calculation parameters with set values
double precision,parameter :: psr_M=1.55*1.3267297e20
double precision,parameter :: G_Msun=1.3267297e20
double precision,parameter :: pc_to_m=3.08e16
! Vector declarations
integer :: irow
double precision :: vfac
double precision, dimension(nrow) :: drx,dry,drz,dvx,dvy,dvz,rmag,jfac,az,jz
! Break up the input array for faster access
double precision,dimension(nrow) :: input_M
double precision,dimension(nrow) :: input_rx
double precision,dimension(nrow) :: input_ry
double precision,dimension(nrow) :: input_rz
double precision,dimension(nrow) :: input_vx
double precision,dimension(nrow) :: input_vy
double precision,dimension(nrow) :: input_vz
input_M(:) = input_array(:,1)*G_Msun
input_rx(:) = input_array(:,2)*pc_to_m
input_ry(:) = input_array(:,3)*pc_to_m
input_rz(:) = input_array(:,4)*pc_to_m
input_vx(:) = input_array(:,5)*1000
input_vy(:) = input_array(:,6)*1000
input_vz(:) = input_array(:,7)*1000
!$OMP PARALLEL DO private(vfac,drx,dry,drz,dvx,dvy,dvz,rmag,jfac,az,jz) shared(output_array) NUM_THREADS(2)
DO irow = 1,nrow
! Get the i-th iteration
vfac = sqrt(input_M(irow)/psr_M)
drx = (input_rx-input_rx(irow))
dry = (input_ry-input_ry(irow))
drz = (input_rz-input_rz(irow))
dvx = (input_vx-input_vx(irow)*vfac)
dvy = (input_vy-input_vy(irow)*vfac)
dvz = (input_vz-input_vz(irow)*vfac)
rmag = sqrt(drx**2+dry**2+drz**2)
jfac = -3*drz/(drx**2+dry**2+drz**2)
! Calculate the acceleration and jerk
az = input_M*(drz/rmag**3)
jz = (input_M/rmag**3)*((dvx*drx*jfac)+(dvy*dry*jfac)+(dvz+dvz*drz*jfac))
! Remove bad index
az(irow) = 0
jz(irow) = 0
output_array(irow,1) = sum(az)
output_array(irow,2) = sum(jz)
END DO
!$OMP END PARALLEL DO
END subroutine calc
下面是一个简单的检查,看看OpenMP线程在Fortran代码中是否确实可见:
module OTmod
!$ use omp_lib
implicit none
public :: get_threads
contains
function get_threads() result(nt)
integer :: nt
nt = 0
!$ nt = omp_get_max_threads()
end function get_threads
end module OTmod
汇编:
> f2py -m OTfor --fcompiler=gfortran --f90flags='-fopenmp' -lgomp -c OTmod.f90
执行:
> python
>>> from OTfor import otmod
>>> otmod.get_threads()
12
您可以通过环境变量OMP_NUM_threads来控制线程数,并在代码中检查OMP_get_max_threads的可用线程数。您应该能够编写
使用OMP_lib
而不是包括“OMP_lib.h”
,最好使用!$使用omp_lib
,也可以在不支持OpenMP的情况下进行编译。@haraldkl,所以我在早期对此进行了测试,代码确实报告说我使用了2个线程(在发布的代码中。我尝试使用不同数量的线程运行代码,以查看会发生什么更改。什么都没有发生。)同时,尝试使用$由于某种原因,使用您提到的omp_lib在我的设置中不起作用(而include确实起作用)。我以前在Fortran脚本上运行过openmp,没有任何include语句,现在添加了这个库,希望它可能是一些奇怪的编译器/包装器特定的东西。调试代码时,我使用了omp_get_num_threads(),并让它在Fortran脚本执行期间打印数字。(技术上我猜是包装后的C。)它报告了正确的数字,尽管在执行过程中没有显示实际线程的证据。@RylkanTiwaz Hm,那么这可能是一个固定问题。您的代码看起来应该受益于多线程,但如果两个线程都在同一个内核上运行,则没有帮助。你能用纯Fortran语言运行这个程序吗,只是为了检查它是否有效?还是在另一台机器上?
> python
>>> from OTfor import otmod
>>> otmod.get_threads()
12