Fortran 使用OpenMP并行时的性能问题
我试图将代码并行化,但这只会降低性能。我写了一个Fortran代码,运行了几个蒙特卡罗积分,然后找到它们的平均值Fortran 使用OpenMP并行时的性能问题,fortran,openmp,intel-fortran,Fortran,Openmp,Intel Fortran,我试图将代码并行化,但这只会降低性能。我写了一个Fortran代码,运行了几个蒙特卡罗积分,然后找到它们的平均值 implicit none integer, parameter :: n=100 integer, parameter :: m=1000000 real, parameter :: pi=3.141592654 real MC,integ,x,y integer tid,OMP_GET_THREAD_N
implicit none
integer, parameter :: n=100
integer, parameter :: m=1000000
real, parameter :: pi=3.141592654
real MC,integ,x,y
integer tid,OMP_GET_THREAD_NUM,i,j,init,inside
read*,init
call OMP_SET_NUM_THREADS(init)
call random_seed()
!$OMP PARALLEL DO PRIVATE(J,X,Y,INSIDE,MC)
!$OMP& REDUCTION(+:INTEG)
do i=1,n
inside=0
do j=1,m
call random_number(x)
call random_number(y)
x=x*pi
y=y*2.0
if(y.le.x*sin(x))then
inside=inside+1
endif
enddo
MC=inside*2*pi/m
integ=integ+MC/n
enddo
!$OMP END PARALLEL DO
print*, integ
end
随着线程数量的增加,运行时间急剧增加。我一直在寻找此类问题的解决方案,在大多数情况下,共享内存元素恰好是问题所在,但我看不出它是如何影响我的案例的
我使用英特尔Fortran编译器在16核处理器上运行它
编辑:添加
隐式无
、声明所有变量并添加private子句后的程序您不应使用随机数
进行高性能计算,并且绝对不能在并行线程中使用。对于随机数生成器的质量和标准随机数生成器的线程安全没有任何保证。看
有些编译器将使用无法并行调用的快速算法。有些编译器的方法速度较慢,但可以从并行调用。有些既快又允许并行。有些会生成质量较差的随机序列,有些会生成质量较好的随机序列
您应该使用一些并行PRNG库。有很多。请参阅此处,了解我在自己的稍加改进的版本中使用基于库的英特尔的建议,但请注意,我不关心应用程序中序列的质量,只关心速度
到旧版本: 你在那里有比赛条件 与 更多线程可以竞争写入和读取变量。您必须以某种方式同步访问。如果您进行了
缩减
,您将遇到以下问题:
integ=integ+MC/n
如果将其设置为私有,则inside=inside+1
将仅在本地计算
MC
似乎也处于争用状态,因为将有更多的线程在其中写入。根本不清楚MC
做什么以及为什么会在那里,因为您没有在任何地方使用该值您确定所显示的代码是否完整吗?如果不完整,请查看如何进行更改
请参阅其他许多示例,了解竞争条件如何使程序变慢。欢迎。请拿这个,这是推荐给所有新来者的。你是如何测量时间的?请看我是如何改变你代码中的缩进的。最好将所有代码缩进,以便人们可以看到结构。这样保存源文件对你也有好处。里面的
是什么?它来自哪里?请确保您使用IMPLICIT NONE
@VladimirF谢谢您的编辑和建议。这个程序用一个线程运行几秒钟,用多个线程运行一分钟多,所以我没有使用任何内置函数来测量时间inside
是位于曲线下的随机点的数量x*sin(x)
其中x从0到pi。生成m
随机点的总面积为2*pi,因此曲线下的面积为inside*(2*pi)/m
,默认情况下,存储在MC
inside
中的面积应为私有变量。我希望外部循环并行运行,这样内部循环就可以在不同的线程中独立运行MC
存储积分值MC
独立计算n次,平均值存储在integ
中。我还尝试删除integ
,以便所有内容都是私有的,只是为了查看时差,但它对运行时没有任何影响。为什么您认为它是私有的默认值?您的代码中没有这样的设置。默认情况下,所有内容都是共享的。我坚信这个程序很慢,因为比赛条件很差。你比较串行和并行代码的结果了吗?它们是相同的还是不同的?我打赌它们会有所不同。我尝试添加了DEFAULT(PRIVATE)
,但没有任何效果(这就是为什么我认为默认情况下它一定是PRIVATE,我的错)。令人惊讶的是,无论是否使用DEFAULT(PRIVATE)
,串行和并行代码的结果都是相同的。此外,结果精确到小数点后3位。我还尝试使用private
子句定义所有private变量,但这也没有帮助。没有任何人可以帮助您。它必须是可编译和完整的。虽然它是从一个更大的代码中的问题中得到启发的,但我使用ifort编译这段代码本身并没有任何问题。我承认它写得不好,可能会使查找问题变得困难。我还想问,虽然在我的机器上使用单线程时,每次迭代都花费了将近一秒钟的时间,但是否可能存在一些开销问题。
integ=integ+MC/n