fortran 2008 do 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
可以按任何顺序完成迭代。您可以阅读更多相关信息here。
据我所知,gfortran不会自动并行化这些do concurrent
循环,而我记得有关gfortran扩散列表的邮件(here)。它只是将它们转换为经典的do
循环。
我的问题:您是否知道系统地并行化do concurrent
循环的方法?例如,使用系统 openmp语法?
答案 0 :(得分:12)
自动执行并不容易。 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 允许 type-spec 允许在头部内定义循环索引,您需要在BLOCK ... END BLOCK
中包围整个内容构造以保留语义。您还需要检查 forall-header 末尾是否存在 scalar-mask-expr ,如果存在,您还应该将IF ... END IF
置于其中最里面的循环。
如果您在DO CONCURRENT
的正文中只有数组赋值,那么您也可以将其转换为FORALL
并使用workshare
OpenMP指令。它会比上面容易得多。
DO CONCURRENT <forall-header>
<block>
END DO
会变成:
!$omp parallel workshare
FORALL <forall-header>
<block>
END FORALL
!$omp end parallel workshare
鉴于上述所有内容,我能想到的唯一系统方式是系统地浏览您的源代码,搜索DO CONCURRENT
和系统地根据 forall-header 和循环体的内容将其替换为上述转换结构之一。
编辑:目前不鼓励使用OpenMP workshare
指令。事实证明,至少英特尔Fortran编译器和GCC序列化FORALL
语句并在OpenMP workshare
指令内构造,在编译期间用OpenMP single
指令包围它们,这不会带来任何加速。其他编译器可能会以不同的方式实现它,但如果要实现便携性能,最好避免使用它。
答案 1 :(得分:1)
我不确定你的意思是“系统地并行化并发循环的方法”。但是,要简单地将一个普通的do
循环与OpenMP并行化,您可以使用类似的东西:
!$omp parallel private (i)
!$omp do
do i = 1,10
array(i) = i
end do
!$omp end do
!$omp end parallel
这就是你想要的吗?