我目前正在使用gfortran 4.9.2,我想知道编译器是否真的知道如何利用DO CONCURRENT构造(Fortran 2008)。我知道编译器"支持"它,但目前尚不清楚这是什么。例如,如果打开自动并行化(指定了一定数量的线程),编译器是否知道如何并行化并发循环?
编辑:正如评论中提到的,this previous question上的SO与我的非常相似,但它是从2012年开始的,只有最新版本的gfortran才能实现现代Fortran的最新功能,所以我认为它值得询问2015年编译器的当前状态。
答案 0 :(得分:0)
gfortran中的DO CONCURRENT
并没有显式启用某些新功能,而是对程序员施加了限制,以便隐式在需要时允许循环并行化(使用选项-ftree-parallelize-loops=NPROC
)。
尽管DO
循环可以包含任何函数调用,但是DO CONCURRENT
的内容仅限于PURE
个函数(即没有副作用)。因此,当有人尝试在RANDOM_NUMBER
中使用PURE
(不是DO CONCURRENT
时,因为它需要保持生成器的状态)时,gfortran会提出抗议:
prog.f90:25:29:
25 | call random_number(x)
| 1
Error: Subroutine call to intrinsic ‘random_number’ in DO CONCURRENT block at (1) is not PURE
否则,DO CONCURRENT
的行为与常规DO
相同。它仅强制使用可并行化的代码,因此-ftree-parallelize-loops=NPROC
成功。例如,对于gfortran 9.1和-fopenmp -Ofast -ftree-parallelize-loops=4
,以下程序中的标准DO
和F08 DO CONCURRENT
循环都在4个线程中运行,并且计时基本相同:
program test_do
use omp_lib, only: omp_get_wtime
integer, parameter :: n = 1000000, m = 10000
real, allocatable :: q(:)
integer :: i
real :: x, t0
allocate(q(n))
t0 = omp_get_wtime()
do i = 1, n
q(i) = i
do j = 1, m
q(i) = 0.5 * (q(i) + i / q(i))
end do
end do
print *, omp_get_wtime() - t0
t0 = omp_get_wtime()
do concurrent (i = 1:n)
q(i) = i
do j = 1, m
q(i) = 0.5 * (q(i) + i / q(i))
end do
end do
print *, omp_get_wtime() - t0
end program test_do