如何并行化总和?来自并行循环和来自礼拜的不同结果

时间:2013-01-04 10:33:05

标签: fortran openmp intel-fortran

正如标题所述,我想使用OpenMP并行化一笔金额。我搜索了不同的方法,但我要么不明白他们做了什么,要么他们没有工作。这是我发现的:

1)

!$OMP PARALLEL WORKSHARE
P_pump_t = 0.5d0 * dcv / pi**2 * sum( k * p_pump_k * dk )
!$OMP END PARALLEL WORKSHARE

有效,但我不明白发生了什么以及我得到了什么好处。

2)

!$OMP PARALLEL DO REDUCTION(+:P_pump_t)
do l = 1, n
P_pump_t = P_pump_t + 0.5d0 * dcv / pi**2 * k(l) * p_pump_k(l) * dk(l)
end do
!$OMP END PARALLEL DO

给出错误(不同于1)或3))结果。

3)当然我可以计算一个新的数组(并行化),最后总结一下......

提示如何做到最好?

1 个答案:

答案 0 :(得分:2)

根据您共享的代码量,我猜“但我不会2”“意味着循环版本会给出不正确的(不同的?)结果。如果您在求和循环之前省略了P_pump_t0.0的初始化,则可能是这样。另请注意,由于浮点运算的非关联性,两个代码可能会产生稍微不同的结果 - 例如,(a+b)+c可能会产生与a+(b+c)略有不同的结果,因为之后应用了舍入和归一化每次操作。这样的东西会更好地匹配代码的矢量化版本:

P_pump_t = 0.0
!$OMP PARALLEL DO REDUCTION(+:P_pump_t)
do l = 1, n
  P_pump_t = P_pump_t + k(l) * p_pump_k(l) * dk(l)
end do
!$OMP END PARALLEL DO
P_pump_t = 0.5d0 * dcv / pi**2 * P_pump_t

很有可能ifort已经在循环之后提取了常见的乘法 - 它非常擅长执行这样的优化。

另请注意,在英特尔的OpenMP实现中,WORKSHARE指令简单地转换为SINGLE,即代码实际上是串行运行的,而且在使用x87 FPU指令的32位机器上可能会产生不同的结果从串行版本而不是多线程版本,因为x87 FPU的内部精度更高。