Arrays 用Fortran实现Openmp阵列精简
我正在尝试将我编写的代码并行化。我在数组上执行还原时遇到问题。对于小型数组来说,这一切似乎都很好,但是当数组大小超过某个点时,我要么会出现堆栈溢出错误,要么会崩溃 我尝试在编译时使用/F增加堆栈大小,在windows上使用ifort,我还尝试将set KMP_STACKSIZE=xxx传递给英特尔特定的堆栈大小偏差。这有时会有帮助,并允许代码在我的循环中继续前进,但最终无法解决问题,即使堆栈大小为1Gb或更大 下面是我的代码的一个小型独立工作示例。它以串行方式工作,只有一个线程。或者有许多线程,但只有一个小“N”。较大的N(如示例中的250000)会导致问题 我不认为这些数组如此庞大以至于会导致重大问题,并且假设增加堆栈空间会有所帮助——是否还有其他选择,或者我是否在编码中遗漏了一些重要的内容Arrays 用Fortran实现Openmp阵列精简,arrays,fortran,openmp,fortran90,reduction,Arrays,Fortran,Openmp,Fortran90,Reduction,我正在尝试将我编写的代码并行化。我在数组上执行还原时遇到问题。对于小型数组来说,这一切似乎都很好,但是当数组大小超过某个点时,我要么会出现堆栈溢出错误,要么会崩溃 我尝试在编译时使用/F增加堆栈大小,在windows上使用ifort,我还尝试将set KMP_STACKSIZE=xxx传递给英特尔特定的堆栈大小偏差。这有时会有帮助,并允许代码在我的循环中继续前进,但最终无法解决问题,即使堆栈大小为1Gb或更大 下面是我的代码的一个小型独立工作示例。它以串行方式工作,只有一个线程。或者有许多线程,
program testreduction
use omp_lib
implicit none
integer :: i, j, nthreads, Nsize
integer iseed /3/
REAL, allocatable :: A(:,:), B(:), C(:), posi(:,:)
REAL :: dx, dy, r, Axi, Ayi, m, F
!Set size of matrix, and main loop
Nsize = 250000
m = 1.0
F = 1.0
!Allocate posi array
allocate(posi(2,Nsize))
!Fill with random numbers
do i=1,Nsize
do j=1,2
posi(j,i) = (ran(iseed))
end do
end do
!Allocate other arrays
allocate(A(2,Nsize), C(Nsize), B(Nsize))
print*, sizeof(A)+sizeof(B)+sizeof(C)
!$OMP parallel
nthreads = omp_get_num_threads()
!$OMP end parallel
print*, "Number of threads ", nthreads
!Go through each array and do some work, calculating a reduction on A, B and C.
!$OMP parallel do schedule(static) private(i, j, dx, dy, r, Axi, Ayi) reduction(+:C, B, A)
do i=1,Nsize
do j=1,Nsize
!print*, i
dx = posi(1,i) - posi(1,j)
dy = posi(2,i) - posi(2,j)
r = sqrt(dx**2+dy**2)
Axi = -m*(F)*(dx/(r))
Ayi = -m*(F)*(dy/(r))
A(1,i) = A(1,i) + Axi
A(2,i) = A(2,i) + Ayi
B(i) = B(i) + (Axi+Ayi)
C(i) = C(i) + dx/(r) + dy/(r)
end do
END DO
!$OMP END parallel do
end program
更新
我所说的一个更好的例子
program testreduction2
use omp_lib
implicit none
integer :: i, j, nthreads, Nsize, q, k, nsize2
REAL, allocatable :: A(:,:), B(:), C(:)
integer, ALLOCATABLE :: PAIRI(:), PAIRJ(:)
Nsize = 25
Nsize2 = 19
q=0
allocate(A(2,Nsize), C(Nsize), B(Nsize))
ALLOCATE(PAIRI(nsize*nsize2), PAIRJ(nsize*nsize2))
do i=1,nsize
do j =1,nsize2
q=q+1
PAIRI(q) = i
PAIRJ(q) = j
end do
end do
A = 0
B = 0
C = 0
!$OMP parallel do schedule(static) private(i, j, k)
do k=1,q
i=PAIRI(k)
j=PAIRJ(k)
A(1,i) = A(1,i) + 1
A(2,i) = A(2,i) + 1
B(i) = B(i) + 1
C(i) = C(i) + 1
END DO
!$OMP END parallel do
PRINT*, A
PRINT*, B
PRINT*, C
END PROGRAM
问题是您正在减少非常大的阵列。请注意,在OpenMP 4.5之前,其他语言(C、C++)无法减少阵列 但是我看不出有任何理由在你的例子中减少,你只更新每个元素一次 试试看
!$OMP parallel do schedule(static) private(i, dx, dy, r, Axi, Ayi)
do i=1,Nsize
do j=1,Nsize
...
A(1,i) = A(1,i) + Axi
A(2,i) = A(2,i) + Ayi
B(i) = B(i) + (Axi+Ayi)
C(i) = C(i) + dx/(r) + dy/(r)
end do
end do
!$OMP END parallel do
关键是螺纹不相交。每个线程使用不同的i
s集合,因此A
、B
和C
的元素也不同
即使你提出了一个似乎必要的案例,你也可以重写它来避免它。您甚至可以自己分配一些缓冲区并模拟减少。或者使用原子更新。在本例中,您是正确的,我不需要减少,但是在实际代码中我需要。这只是我能想到的以同样方式失败的最简单的例子。仍然没有必要减少你的更新。如果你有不同的东西,展示出来。还是太简单了,
PAIRI
只依赖于i
,而你不使用j
。不需要削减。显示实际的代码。也许我没有得到这个,但是如果两个线程都有相同的I值并尝试写入相同的元素,这不是一个问题吗?奇怪的是,所有的大数组都是可分配的。在reduce子句中列出它们不应该导致堆栈空间耗尽,因为私有副本也应该是可分配的。