10

fortran 2008do concurrent构造是一个 do 循环,它告诉编译器没有迭代影响任何其他迭代。因此可以安全地并行化。

一个有效的例子:

program main
  implicit none
  integer :: i
  integer, dimension(10) :: array
  do concurrent( i= 1: 10)
    array(i) = i
  end do
end program main

可以按任何顺序进行迭代。你可以在这里阅读更多关于它的信息。

据我所知,gfortran 不会自动并行化这些do concurrent循环,而我记得有一封关于这样做的 gfortran-diffusion-list 邮件(此处)。它只是将它们转换为经典do循环。

我的问题:你知道系统地并行化do concurrent循环的方法吗?例如使用系统的openmp 语法?

4

2 回答 2

14

自动做到这一点并不容易。该DO CONCURRENT构造有一个forall-header,这意味着它可以接受多个循环、索引变量定义和一个掩码。基本上,您需要更换:

DO CONCURRENT([<type-spec> :: ]<forall-triplet-spec 1>, <forall-triplet-spec 2>, ...[, <scalar-mask-expression>])
  <block>
END DO

和:

[BLOCK
    <type-spec> :: <indexes>]

!$omp parallel do
DO <forall-triplet-spec 1>
  DO <forall-triplet-spec 2>
    ...
    [IF (<scalar-mask-expression>) THEN]
      <block>
    [END IF]
    ...
  END DO
END DO
!$omp end parallel do

[END BLOCK]

(方括号中的内容是可选的,基于forall-header中相应部分的存在)

请注意,这不如将一个大循环与<iters 1>*<iters 2>*...独立迭代并行化那样有效,而这DO CONCURRENT是预期的。另请注意,forall-header允许一种类型规范,该规范允许在标头内定义循环索引,并且您需要将整个事物包围在BLOCK ... END BLOCK构造中以保留语义。您还需要检查scalar-mask-expr是否存在于forall-header的末尾,如果存在,您还应该将其IF ... END IF放在最内层循环中。

如果您的主体内只有数组分配,DO CONCURRENT您也可以将其转换为FORALL并使用workshareOpenMP 指令。它会比上面的要容易得多。

DO CONCURRENT <forall-header>
  <block>
END DO

会成为:

!$omp parallel workshare
FORALL <forall-header>
  <block>
END FORALL
!$omp end parallel workshare

鉴于以上所有情况,我能想到的唯一系统方法是系统地检查您的源代码,根据forall-header和循环体的内容,搜索DO CONCURRENT系统地用上述转换后的结构之一替换它。

编辑:workshare目前不鼓励使用 OpenMP指令。事实证明,至少英特尔 Fortran 编译器和 GCC通过在编译期间用 OpenMP 指令包围它们来序列化 OpenMP 指令中的FORALL语句和构造,这不会带来任何加速。其他编译器可能会以不同的方式实现它,但如果要实现可移植性能,最好避免使用它。worksharesingle

于 2012-07-19T08:52:03.947 回答
2

我不确定您的意思是“一种系统地并行化并发循环的方法”。但是,要简单地将普通do循环与 OpenMP 并行化,您可以使用以下内容:

!$omp parallel private (i)
!$omp do
do i = 1,10
    array(i) = i
end do
!$omp end do
!$omp end parallel

这就是你所追求的吗?

于 2012-07-18T21:43:44.413 回答