Fortran 使用OpenMP减少阵列的最佳方法是什么?
我正在使用OpenMP和Fortran。我已经把我的用例归结为一个非常简单的例子。我有一个自定义派生类型的对象数组,每个对象都包含一个大小不同的数组。我希望确保无论循环中发生什么,我都会对向量对象的所有Fortran 使用OpenMP减少阵列的最佳方法是什么?,fortran,openmp,Fortran,Openmp,我正在使用OpenMP和Fortran。我已经把我的用例归结为一个非常简单的例子。我有一个自定义派生类型的对象数组,每个对象都包含一个大小不同的数组。我希望确保无论循环中发生什么,我都会对向量对象的所有值数组组件应用缩减: program main implicit none integer :: i type vector real,allocatable :: values(:) end type vector type(vector) :: vecto
值数组组件应用缩减:
program main
implicit none
integer :: i
type vector
real,allocatable :: values(:)
end type vector
type(vector) :: vectors(3)
allocate(vectors(1)%values(3))
vectors(1)%values = 0
allocate(vectors(2)%values(6))
vectors(2)%values = 0
allocate(vectors(3)%values(9))
vectors(3)%values = 0
!$OMP PARALLEL REDUCTION(+:vectors%values)
!$OMP DO
do i=1,1000
vectors(1)%values = vectors(1)%values + 1
vectors(2)%values = vectors(2)%values + 2
vectors(3)%values = vectors(3)%values + 3
end do
!$OMP END DO
!$OMP END PARALLEL
print*,sum(vectors(1)%values)
print*,sum(vectors(2)%values)
print*,sum(vectors(3)%values)
end program main
在这种情况下,减少(+:vectors%values)
不起作用,因为我得到以下错误:
test2.f90(22): error #6159: A component cannot be an array if the encompassing structure is an array. [VALUES]
!$OMP PARALLEL REDUCTION(+:vectors%values)
-------------------------------------^
test2.f90(22): error #7656: Subobjects are not allowed in this OpenMP* clause; a named variable must be specified. [VECTORS]
!$OMP PARALLEL REDUCTION(+:vectors%values)
-----------------------------^
compilation aborted for test2.f90 (code 1)
我尝试重载向量类型的+
的含义,然后指定减少(+:vectors)
,但仍然得到:
test.f90(43): error #7621: The data type of the variable is not defined for the operator or intrinsic specified on the OpenMP* REDUCTION clause. [VECTORS]
!$OMP PARALLEL REDUCTION(+:vectors)
-----------------------------^
建议使用什么方法来处理此类派生类型并使约简生效
仅供参考,在没有OpenMP的情况下编译时,正确的输出是
3000.000
12000.00
27000.00
这不仅仅是OpenMP问题,如果值
是可分配数组组件,则不能将向量%values
作为一个实体引用,因为Fortran 2003的规则禁止这样做。这是因为这样的数组在内存中不会有任何规则的跨步,所以可分配组件存储在随机地址中
如果包围数组的元素数很小,可以这样做
!$OMP PARALLEL REDUCTION(+:vectors(1)%values,vectors(2)%values,vectors(3)%values)
!$OMP DO
do i=1,1000
vectors(1)%values = vectors(1)%values + 1
vectors(2)%values = vectors(2)%values + 2
vectors(3)%values = vectors(3)%values + 3
end do
!$OMP END DO
!$OMP END PARALLEL
否则,您必须进行另一个循环,比如说j
,并使reduce正好向量(j)%value
如果编译器不接受reduction子句中的结构组件(必须研究最新的标准,看看它是否被放宽),您可以采取变通办法
!$OMP PARALLEL
do j = 1, size(vectors)
call aux(vectors(j)%values)
end do
!$OMP END PARALLEL
contains
subroutine aux(v)
real :: v(:)
!$OMP DO REDUCTION(+:v)
do i=1,1000
v = v + j
end do
!$OMP END DO
end subroutine
关联或指针会更简单,但它们也不允许使用。作为替代,您可以始终使用临时数组和关键部分实现自己的缩减:
program main
implicit none
integer :: i
type vector
real,allocatable :: values(:)
end type vector
type(vector) :: vectors(3)
type(vector),allocatable :: tmp(:)
allocate(vectors(1)%values(3))
vectors(1)%values = 0
allocate(vectors(2)%values(6))
vectors(2)%values = 0
allocate(vectors(3)%values(9))
vectors(3)%values = 0
!$OMP PARALLEL PRIVATE(TMP)
! Use a temporary array to hold the local sum
allocate( tmp(size(vectors)) )
do i=1,size(tmp)
allocate( tmp(i)%values( size(vectors(i)%values )) )
tmp(i)%values = vectors(i)%values
enddo ! i
!$OMP DO
do i=1,1000
tmp(1)%values = tmp(1)%values + 1
tmp(2)%values = tmp(2)%values + 2
tmp(3)%values = tmp(3)%values + 3
end do
!$OMP END DO
! Get the global sum one thread at a time
!$OMP CRITICAL
vectors(1)%values = vectors(1)%values + tmp(1)%values
vectors(2)%values = vectors(2)%values + tmp(2)%values
vectors(3)%values = vectors(3)%values + tmp(3)%values
!$OMP END CRITICAL
deallocate(tmp)
!$OMP END PARALLEL
print*,sum(vectors(1)%values)
print*,sum(vectors(2)%values)
print*,sum(vectors(3)%values)
end program main
通过在向量的所有元素上循环,可以更有效地排列此代码段。然后,tmp
可以是标量 向量(1)%value
似乎未被识别为有效语法。如果我尝试用gfortran 4.9.3编译它,我会在OpenMP变量列表中得到语法错误。这对您有效吗?如果有效,您使用什么编译器?这是因为语法检查器需要变量名而不是表达式。您可以在gfortran-4.8中使用associate作为变通方法,但更高版本不喜欢它。@请参阅使用内部过程的变通方法。