一般而言,如果您显式指导编译器对循环进行并行化,编译器就会执行。但也有例外情况-存在一些编译器不进行并行化的循环。
下面是可检测到的主要抑制因素,这些抑制因素可以防止对 DO 循环进行显式并行化:
DO 循环嵌套在已并行化的另一 DO 循环内。
该例外情况也适用于间接嵌套。如果显式并行化包含子例程调用的循环,那么,即使要求编译器并行化该子例程中的循环,这些循环在运行时也不会以并行方式运行。
流控制语句允许跳出 DO 循环。
循环的索引变量受副作用影响,例如被等价。
通过使用 -vpara 和 -loopinfo 进行编译,可以得到诊断消息,指出在显式并行化循环过程中编译器是否检测到问题。
下表列出了编译器检测到的典型并行化问题:
表 10–3 显式并行化问题|
问题 |
已并行化 |
警告消息 |
|---|---|---|
|
循环嵌套在并行化了的另一循环内。 |
否 |
否 |
|
循环在并行化循环体内调用的某个子例程中。 |
否 |
否 |
|
流控制语句允许跳出循环。 |
否 |
是 |
|
循环的索引变量受副作用影响。 |
是 |
否 |
|
循环中的某变量具有循环携带依赖性。 |
是 |
是 |
|
在循环中使用 I/O 语句-通常是不明智的,因为输出顺序无法预料。 |
是 |
否 |
示例:嵌套循环:
...
!$OMP PARALLEL DO
do 900 i = 1, 1000 ! Parallelized (outer loop)
do 200 j = 1, 1000 ! Not parallelized, no warning
...
200 continue
900 continue
...
|
示例:子例程中已并行化的循环:
program main
...
!$OMP PARALLEL DO
do 100 i = 1, 200 <-parallelized
...
call calc (a, x)
...
100 continue
...
subroutine calc ( b, y )
...
!$OMP PARALLEL DO
do 1 m = 1, 1000 <-not parallelized
...
1 continue
return
end
|
在此例中,由于子例程本身是以并行方式运行的,所以子例程中的循环未被并行化。
示例:跳出循环:
!$omp parallel do
do i = 1, 1000 ! <- Not parallelized, error issued
...
if (a(i) .gt. min_threshold ) go to 20
...
end do
20 continue
...
|
如果标记进行并行化的循环外有转跳,编译器会发出诊断错误。
示例:循环中的某个变量具有循环携带依赖性:
demo% cat vpfn.f
real function fn (n,x,y,z)
real y(*),x(*),z(*)
s = 0.0
!$omp parallel do private(i,s) shared(x,y,z)
do i = 1, n
x(i) = s
s = y(i)*z(i)
enddo
fn=x(10)
return
end
demo% f95 -c -vpara -loopinfo -openmp -O4 vpfn.f
"vpfn.f", line 5: Warning: the loop may have parallelization inhibiting reference
"vpfn.f", line 5: PARALLELIZED, user pragma used
|
在此,循环被并行化,但在警告中诊断出可能的循环携带依赖性。但要注意,编译器并不能诊断出所有循环依赖性。