【发布时间】:2017-05-07 12:47:01
【问题描述】:
在我的 Fortran 95 代码中,我有一系列嵌套的 DO 循环,整个循环需要大量时间来计算,因此我想使用 OpenMP 添加并行功能(使用 gfortran -fopenmp 编译/构建)。
有一个主 DO 循环,运行 1000 次。
其中有一个子 DO 循环,运行 100 次。
其中嵌套了其他几个DO循环,迭代次数随着DO循环的每次迭代而增加(第一次一次,最后一次最多1000次)。
例子:
DO a = 1, 1000
DO b = 1, 100
DO c = 1, d
some calculations
END DO
DO c = 1, d
some calculations
END DO
DO c = 1, d
some calculations
END DO
END DO
d = d + 1
END DO
一些嵌套的 DO 循环必须串行运行,因为它们本身包含依赖项(也就是说,循环的每次迭代都有一个包含上一次迭代的值的计算),并且不容易并行化在这种情况下。
我可以轻松地使没有任何依赖关系的循环并行运行,如下所示:
d = 1
DO a = 1, 1000
DO b = 1, 100
DO c = 1, d
some calculations with dependencies
END DO
!$OMP PARALLEL
!$OMP DO
DO c = 1, d
some calculations without dependencies
END DO
!$OMP END DO
!$OMP END PARALLEL
DO c = 1, d
some calculations with dependencies
END DO
END DO
d = d + 1
END DO
但是我知道打开和关闭并行线程会有很大的开销,因为这在循环中发生了很多次。当顺序运行时,代码的运行速度比以前慢得多。
在此之后,我认为打开和关闭主循环任一侧的并行代码是有意义的(因此只应用一次开销),并将线程数设置为 1 或 8 以控制节是否顺序或并行运行,如下:
d = 1
CALL omp_set_num_threads(1)
!$OMP PARALLEL
DO a = 1, 1000
DO b = 1, 100
DO c = 1, d
some calculations with dependencies
END DO
CALL omp_set_num_threads(4)
!$OMP DO
DO c = 1, d
some calculations without dependencies
END DO
!$OMP END DO
CALL omp_set_num_threads(1)
DO c = 1, d
some calculations with dependencies
END DO
END DO
d = d + 1
END DO
!$OMP END PARALLEL
但是,当我将其设置为运行时,我并没有获得运行并行代码所期望的加速。我希望前几个会慢一些来解决开销,但过了一段时间我希望并行代码比顺序代码运行得更快,但事实并非如此。对于DO a = 1, 50,我比较了主 DO 循环每次迭代的运行速度,结果如下:
Iteration Serial Parallel
1 3.8125 4.0781
2 5.5781 5.9843
3 7.4375 7.9218
4 9.2656 9.7500
...
48 89.0625 94.9531
49 91.0937 97.3281
50 92.6406 99.6093
我的第一个想法是我没有正确设置线程数。
问题:
- 我构建并行代码的方式是否有明显问题?
- 有没有更好的方法来实现我已经完成/想要做的事情?
【问题讨论】:
-
您已将并行设置始终设置为 1 个线程。
-
你能具体说明一下我是在哪里做的吗?
标签: loops parallel-processing fortran openmp gfortran