我对Fortran还是很陌生,并且正在开展一项涉及通过OpenMP并行求和数字的练习。
我被告知以下代码正确地计算了通过OpenMP并行计算的数字之和
graph->edge.size()
如果我调整了上面的代码以便可以在自己的Fortran程序中运行它,则会产生
!$omp parallel do private (I)
!$omp+ reduction(+:totals)
do I=1,100
totals = totals + localsum(I)
enddo
!$omp end parallel do
该程序返回
Program test
implicit none
real totals
double precision, dimension (1 : 100) :: localsum
integer I
!$omp parallel do private (I)
!$omp+ reduction(+:totals)
do I=1,100
localsum(I)=I
totals = totals + localsum(I)
enddo
!$omp end parallel do
print *, 'The calculated sum total is', totals
end
但是,我不确定为什么需要为此添加额外的行
The calculated sum total is 5050.00000
当原始代码没有此行时。我注意到,如果我删除
localsum(I)=I
然后
!$omp+ reduction(+:totals)
返回
Program test
implicit none
real totals
double precision, dimension (1 : 100) :: localsum
integer I
!$omp parallel do private (I)
do I=1,100
localsum(I)=I
totals = totals + localsum(I)
enddo
!$omp end parallel do
print *, 'The calculated sum total is', totals
end
当计算的总数应该是错误的。为了计算正确的总数,必须包括减少量 The calculated sum total is 5050.00000
。
是否有另一种方法来调整do循环以匹配提供的原始代码?我不确定为什么必须更改
!$omp+ reduction(+:totals)
到
do I=1,100
totals = totals + localsum(I)
enddo
为了计算局部和。
答案 0 :(得分:3)
这是Odd results with !$omp reduction in Fortran OpenMP的副本。
根据OpenMP规范(p。42),OpenMP伪指令的正确延续是在上一行的末尾使用MediaProjectionManager.createScreenCaptureIntent();
,在延续行使用&
( !$omp&
是可选的)。因此,您的代码应如下所示:
!$omp&
由于编译器忽略了定义Program test
implicit none
real totals
integer I
integer, dimension(100) :: localsum
!$omp parallel do private (I) &
!$omp& reduction(+:totals)
do I=1,100
localsum(I)=I
totals = totals + localsum(I)
enddo
!$omp end parallel do
print *, 'The calculated sum total is', totals
end
变量归约的续行,因此您得到了任意结果。添加正确的延续后,我得到正确的结果:
totals
答案 1 :(得分:0)
有无!$omp+ reduction(+:totals)
,执行的代码是不同的。
没有此指令,您将直接更新全局变量totals
。这可能有效(在您的示例中有效),但远不能保证。问题在于这可能导致比赛。
假设线程a和线程b要更新此变量。他们需要:
1.从内存中获取var
2.在处理器中进行更新
3.将其写回内存
线程a和b中这些操作的相对顺序是什么?未指定。
如果顺序为1a2a3a1b2b3b,则没有问题。
如果它是1a1b2a2b3a3b,则会出现问题:1a1b(线程a和b取相同的值)2a2b(它们或多或少地同时更新它)3a3b(线程a写入结果并被线程b值覆盖)。>
为避免这种情况,您可以使用原子操作,以确保不会中断读取-修改-写入周期,但是这非常昂贵,并且可能会大大降低执行时间。
为避免这种情况,必须使用减少量。第!$omp+ reduction(+:totals)
行告诉openmp以安全有效的方式进行还原。实际要做的是
totals
中:原子操作将以正确更新全局变量的方式执行,并避免线程之间的竞争。仍然有原子更新,但数量减少了,并且累积主要通过快速的本地操作来完成。
关于行localsum(I)=I
的有用性,要求向量localsum
事先未初始化。但是,如果目标只是添加第一个整数,则可以使用
do I=1,100
totals = totals + I
enddo
性能将得到改善,结果是相同的。而且两个循环都以类似的方式并行化。