parallel-processing - 如何删除 Fortran 竞争条件?

标签 parallel-processing fortran openmp race-condition

如果这实际上不是竞争条件,请原谅我;我不太熟悉这些术语。

我遇到的问题是此代码在启用 OpenMP 的情况下运行速度较慢。我认为循环应该足够大 (k=100,000),所以我认为开销不是问题。

据我所知,这里出现了竞争条件,因为所有循环都试图一直访问相同的 v(i,j) 值,从而减慢了代码速度。

这里最好的解决方法是创建与线程一样多的 v() 数组副本,并让每个线程访问不同的线程吗?

我在 16 核上使用英特尔编译器,它的运行速度比在单核上稍慢。 谢谢大家!

!$OMP PARALLEL DO

Do 500, k=1,n

Do 10, i=-(b-1),b-1
 Do 20, j=-(b-1),b-1
 if (abs(i).le.l.and.abs(j).eq.d) then
    cycle
 endif
 v(i,j)=.25*(v(i+1,j)+v(i-1,j)+v(i,j+1)+v(i,j-1))

 if (k.eq.n-1) then
    vtest(i,j,1)=v(i,j)
endif
if (k.eq.n) then
    vtest(i,j,2)=v(i,j)
endif
 20 continue
10 continue

500 continue

!$OMP END PARALLEL DO

最佳答案

您肯定编写了竞争条件,但我不确定这是导致您的程序无法更快执行的原因。这条线

v(i,j)=.25*(v(i+1,j)+v(i-1,j)+v(i,j+1)+v(i,j-1))

将由所有线程为 ij 的相同(一组)值执行,这就是竞速发生的地方。鉴于您的程序没有做任何事情来协调对 v 元素的读取和写入,您的程序在实践中是不确定的,因为无法知道 v< 的更新顺序 制作。

您应该在检查程序结果时观察到这种不确定性,并且注意到更改线程数也会对结果产生影响。话又说回来,通过对数组进行长时间运行的模板操作,结果可能会收敛到相同(或足够相似)的值。

OpenMP 为您提供了协调变量访问的工具,但它不会自动实现它们;幕后肯定没有任何事情可以防止对 v 的准同步读取和写入。因此,缺乏性能改进的解释在别处。这可能归因于多线程对系统内存层次结构中某个级别缓存的影响。一个很好的、缓存友好的、按内存顺序遍历数组的每个元素的串行程序变成了一场暴风雪(就缓存而言)随机访问内存,每次都需要访问 RAM。

解释可能在别处。如果执行 OpenMP 版本的时间比执行串行版本的时间稍长,我怀疑该程序实际上并未并行执行。未能正确编译是一个常见的原因(此处为 SO)。

如何解决这个问题?

OpenMP 跨数组的常用模式是在其中一个数组索引上并行化。声明

!$omp parallel do
do i=-(b-1),b-1
....
end do

确保每个线程为 i 获取一组不同的值,这意味着它们写入 v 的不同元素,消除(几乎)数据竞争。在您编写程序时,每个线程都获得一组不同的 k 值,但在内部循环中没有(太多)使用。

顺便说一下,测试

if (k==n-1) then

if (k==n) then

在每次迭代中,您似乎都在为您的程序绑定(bind)一个 anchor ,为什么不呢

do k=1,n-2

并在循环结束时处理对 vtest 的更新。

你可以像这样分开 !$omp parallel do

!$omp parallel
do k=1,n-2

    !$omp do
    do i=-(b-1),b-1

(并在并行循环和区域的末尾进行相应的更改)。现在所有线程都执行并行区域的全部内容,但每个线程都有自己的一组 i 值来使用。我建议您在指令中添加子句以指定每个变量的可访问性(例如 privateshared);但是这个答案有点太长了,我不会详细介绍这些。或者使用 schedule 子句。

当然,最后,即使有我建议的更改,你的程序也将是不确定的,因为这个声明

v(i,j)=.25*(v(i+1,j)+v(i-1,j)+v(i,j+1)+v(i,j-1))

将从 v 读取相邻元素,这些元素由另一个线程更新(在您无法控制的时候)。要解决这个问题……必须回去工作。

关于parallel-processing - 如何删除 Fortran 竞争条件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20413625/

相关文章:

multithreading - 带有 OpenMP 的 OpenGL 总是出现段错误

linux - 来自 PC 生态系统的强大计算能力

c# - 我怎样才能更快地运行这个 Entity Framework 示例

c++ - openMP的并行化效率

pointers - 指向对象的类型变量 - Fortran

fortran - Fortran 中写入磁盘的效率

使用 MPI/OpenMP 的派生数据类型(嵌套类对象)容器的 C++ 程序

pandas - 如何在 dask 中并行化 groupby()?

algorithm - 雅可比方法先收敛再发散

multithreading - OpenMP while 循环