parallel-processing - OpenMP - Fortran 中的任务依赖性

标签 parallel-processing fortran openmp

我目前正在尝试使用 OpenMP 4.0 的 task 结构,包括 Fortran 代码的 depend 语句。因此,我创建了以下示例,该示例应通过任务用数字 1 到 M 填充矩阵的第一行,并在每次第一行中的元素准备就绪时通过任务填充剩余元素。这会产生以下代码:

PROGRAM OMP_TEST 
    IMPLICIT NONE 

    INTEGER K,L 
    INTEGER M
    PARAMETER (M = 8)
    INTEGER A(M,M) 

    A(1:M, 1:M) = 0

    !$omp parallel 
    !$omp single
    DO L=1, M 
        !$omp task depend(out:A(1,L)) default(shared) 
        A(1,L) = L
        !$omp end task 
        DO K = 2, M 
            !$omp task depend(in:A(1,L)) default(shared)
            A(K,L) = A(1,L) 
            !$omp end task
        END DO 
    END DO 
    !$omp taskwait 
    !$omp end single 
    !$omp end parallel

    DO K =1 , M 
        WRITE(*,*) A(K,1:M) 
    END DO 
END PROGRAM 

使用 Intel Fortran 15 编译器进行编译,根据文档了解 depend 语句。但每次执行时打印到屏幕上的结果都是不同的。甚至矩阵的初始零也保留在某些位置。例如:

       1           2           3           4           5           6
       7           8
       0           0           0           0           0           0
       0           0
       0           0           3           4           0           0
       0           8
       1           0           3           4           0           6
       0           8
       1           0           3           4           5           6
       0           8
       1           2           3           4           5           6
       7           8
       0           2           3           4           5           6
       7           0
       1           2           3           4           5           6
       0           8

为什么任务之间的依赖关系没有像我预期的那样正常工作,使得每行中都有值 1 到 8?

最佳答案

声明

!$omp task depend(in:A(1,L)) default(shared)
A(K,L) = A(1,L)
!$omp end task

K 视为共享,但在该任务执行时,K 的值可能已在其他地方修改(事实上,这可能仅由于线程而发生)执行单个 - 循环 DO K = 2,M)。您可以通过将 firstprivate 子句添加到 !$omp 构造中来解决此问题。此子句确保 K 是私有(private)的,但每当创建该任务时也会继承该值。

这一事实同样适用于 L 中的相同语句以及前面几行的任务。以下代码对我使用英特尔 Fortran 编译器版本 16.0 有效。

PROGRAM OMP_TEST
  IMPLICIT NONE

  INTEGER K,L
  INTEGER M
  PARAMETER (M = 8)
  INTEGER A(M,M)

  A(1:M, 1:M) = 0

  !$omp parallel
  !$omp single
  DO L=1, M
      !$omp task depend(out:A(1,L)) default(shared) firstprivate(L)
      A(1,L) = L
      !$omp end task
      DO K = 2, M
          !$omp task depend(in:A(1,L)) default(shared) firstprivate(K,L)
          A(K,L) = A(1,L)
          !$omp end task
      END DO
  END DO
  !$omp taskwait
  !$omp end single
  !$omp end parallel

  DO K =1 , M
      WRITE(*,*) A(K,1:M)
  END DO
END PROGRAM

更新

在研究了 Grisu 引用英特尔示例的评论后,我意识到 KL 应该已经是 firstprivate 因为它们是DO中的循环变量。但是,添加 default(shared) 似乎会改变这种行为。以下代码已明确声明共享变量并已删除 default ,该代码也适用于英特尔 Fortran 16.0。

PROGRAM OMP_TEST
  IMPLICIT NONE

  INTEGER K,L
  INTEGER M
  PARAMETER (M = 8)
  INTEGER A(M,M)

  A(1:M, 1:M) = 0

  !$omp parallel
  !$omp single
  DO L=1, M
      !$omp task depend(out:A(1,L)) shared(A)
      A(1,L) = L
      !$omp end task
      DO K = 2, M
          !$omp task depend(in:A(1,L)) shared(A)
          A(K,L) = A(1,L)
         !$omp end task
      END DO
  END DO
  !$omp taskwait
  !$omp end single
  !$omp end parallel

  DO K =1 , M
      WRITE(*,*) A(K,1:M)
  END DO
END PROGRAM

关于parallel-processing - OpenMP - Fortran 中的任务依赖性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38782836/

相关文章:

class - Fortran函数一次性获取指针的关联状态和大小

openmp - 使用 openMP 的曼德尔布罗

javascript - 带返回值的 Promise 并行执行

c - openMP 线程和迭代

performance - 优化循环 : huge arrays operations

compiler-errors - 编译错误: “_for_stop_core” not found

c++ - 带有 For 循环和指针操作的 OPENMP

c - 对多线程应用程序使用 perf stat

java - 如何在 mapreduce Hadoop 中执行类似于 SQL 的 Between Operator

c++ - 当构建显示 "loop parallelized"时,为什么 CPU 不会超过 25%