0

这是在 F90 中,但问题适用于任何支持 OpenMP 的语言。为需要多个存储阵列进行时间集成的模拟代码构建数据的典型方法是(目前为二维):

REAL, DIMENSION(imax,jmax,n_sub_timesteps) :: vars

然后将使用以下内容进行更新:

DO J = 1, jmax
  DO I = 1, imax
    vars(I,J,2) = func(vars(:,:,1))
  END DO
END DO

根据我的经验,OpenMP 实际上不会并行化这些循环,因为它认为vars不是线程安全的。但对程序员来说,显然是这样。

让我们假设进一步的实际情况,使vars线程本地化太昂贵而无法将数据复制到其中。

那么,有没有办法温和地暗示(又名强制)OpenMP 不锁定vars,因为它可能无法确定没有线程依赖问题但实际上没有?我知道有办法告诉它某些东西不是线程安全的并且需要锁定,但是有没有办法在不为每个线程制作副本的情况下指定逆向?

4

1 回答 1

3

看起来您将 OpenMP 误认为是自动并行化。我不知道任何执行数据锁定的 OpenMP 实现,除非通过引入部分或语句(或在带有子句的并行区域的末尾)明确告知。OpenMP 编译器不会检查您的代码是否存在可能的数据依赖关系,也不会阻止您并行运行 - 这完全由您决定。如果您想进行不受保护的并发访问,您可以这样做,并且没有支持 OpenMP 的编译器会阻止您这样做。以下代码将始终生成一个并行区域,并将外部循环分配给团队中的线程:CRITICALATOMICREDUCTION

!$OMP PARALLEL DO PRIVATE(I)
DO J = 1, jmax
  DO I = 1, imax
    vars(I,J,2) = func(vars(:,:,1))
  END DO
END DO
!$OMP END PARALLEL DO

另一方面,大多数编译器中的内置自动并行器非常保守和谨慎,通常不会在没有程序员明确提示的情况下并行化像您这样的案例。这些提示通常采用编译器特定指令的形式(在 Fortran 中格式化为注释或在 C/C++ 中格式化为 pragma)。例如,英特尔 Fortran 支持!DEC$ PARALLEL提示它忽略指令后循环中假定的数据依赖关系的指令:

!DEC$ PARALLEL
DO J = 1, jmax
  DO I = 1, imax
    vars(I,J,2) = func(vars(:,:,1))
  END DO
END DO

许多编译器重用其 OpenMP 实现和运行时库以实现自动并行化功能,因此生成的可执行文件的工作通常由 OpenMP 环境变量(如OMP_NUM_THREADS.

如果您的并行 OpenMP 程序运行速度比预期慢,还有许多其他原因,主要与错误共享、缓存垃圾、TLB 垃圾、内存带宽限制、NUMA 系统上的非本地内存访问、使用非临时加载/存储共享变量等,因此看起来 OpenMP 正在执行自动数据锁定,但实际上并没有。

于 2012-11-30T10:56:41.937 回答