并行 fortran 程序将在某个时间休眠
Posted
技术标签:
【中文标题】并行 fortran 程序将在某个时间休眠【英文标题】:parallel fortran program willl sleep at a certain time 【发布时间】:2015-11-05 09:05:28 【问题描述】:最近我不得不将一个用 fortran 编写的串行程序更改为并行版本,以便更快地获得结果。但是我遇到了一些问题。
我使用的是 ubuntu os 和 gfortran 编译器,至于并行 API,我使用的是 OpeMP。在以前的(串行)版本中,我使用许多模块来共享数据,但在 openmp 版本中,我将变量设置为线程私有属性,其中一些变量具有可分配属性。在之前的版本中,我在do-loop之前为变量分配了空间,但是在openmp版本中,如果我这样做,程序会报错为无效的内存引用,虽然我给了它threadprivate属性。所以我在循环中分配变量并在循环中释放它。我在并行区域中进行了循环。它没有错误,程序可以运行。但是还有另一个问题。由于它运行大约 800 分钟 cpu 时间,我使用 ps -ux 命令查看这个并行程序的状态,它的状态从 Rl 变为 Sl。我搜索S的意思,它代表
可中断睡眠(等待事件完成)
那么为什么会出现这个问题呢?是因为我经常分配和释放空间吗?以下是示例代码:
module variables
real, dimension(:), allocatable, save :: a
real, dimension(:,:), allocatable, save :: b
!$omp threadprivate(a,b)
integer, parameter :: n=100
contains
subroutine alloc_var
integer :: status
allocate(a(100),stat=status)
allocate(b(100:100),stat=status)
end subroutine
subroutine free_var
integer :: status
deallocate(a,stat=status)
deallocate(b,stat=status)
end subroutine
end module
对于其他子程序,有一些使用变量a和b。
subroutine cal_sth
use variables, only a
...
end subroutine
串行版主程序
program main
implicit none
external :: cal_sth
use variables, only alloc_var,free_var
integer :: i, j
call alloc_var
do j=1, count1
...
other expresion ...
do i=1, count2
call cal_sth
end do
end do
call free_var
end program
对于平行区域,
program main
implicit none
external :: cal_sth
use variables, only alloc_var, free_var
integer :: i,j
!$omp parallel do private(i,j)
do j=1, count1
...
other expression ...
do i=1, count2
call alloc_var
call cal_sth
if (logical expression) then
call free_var
cycle
end if
call free_var
end do
end do
end program
【问题讨论】:
为什么不在一个专用的parallel
区域内一劳永逸地初始化a
和b
?喜欢:!$omp parallel
call alloc_var
!$omp end parallel
【参考方案1】:
要么拆分组合的parallel do
指令并重写并行循环,因此:
!$omp parallel
call alloc_var
!$omp do
do i=1, count
call cal_sth
end do
!$omp end do
call free_var
!$omp end parallel
或根据 Gilles 的评论使用专用的并行区域:
program main
implicit none
external :: cal_sth
use variables, only alloc_var, free_var
integer :: i
!$omp parallel
call alloc_var
!$omp end parallel
...
!$omp parallel do
do i=1, count
call cal_sth
end do
!$omp end parallel do
...
! other OpenMP regions
...
!$omp parallel
call free_var
!$omp end parallel
end program
【讨论】:
如果我拆分parallel do
指令还有一个问题,因为在并行区域,有些情况我需要cycle
循环,我忘记在示例代码中添加。此外,不仅有一个循环。我将示例代码更改一下,请再看一遍。【参考方案2】:
对于您更新的代码,我认为您有两条不同的途径可以探索提高性能:
内存分配:如前所述,对alloc_var
和free_var
的调用只需要在parallel
区域内进行,但绝对不一定在do
循环内。通过将parallel do
拆分为parallel
,然后是do
,它为您提供了在进入循环之前调用alloc_var
和在退出循环之后调用free_var
的空间。并且可能提前退出内部循环,可能需要释放/重新分配内存本身并不是阻止您这样做的约束。 (有关如何完成此操作的示例,请参见下面的代码)
调度:一些内部迭代的提前终止可能会转化为线程之间的负载不平衡。这可以解释你实验的等待时间。将调度显式设置为dynamic
可能会减少这种影响并提高性能。这需要进行一些试验才能找到要应用的最佳调度策略,但dynamic
似乎是一个很好的起点。
所以这是你的代码,一旦这两个想法实现,它可能看起来像:
program main
implicit none
external :: cal_sth
use variables, only alloc_var, free_var
integer :: i,j
!$omp parallel schedule(dynamic)
call alloc_var
!$omp do private(i,j)
do j=1, count1
...
other expression ...
do i=1, count2
call cal_sth
if (logical expression) then
!uncomment these only if needed for some reasons
!call free_var
!call alloc_var
cycle
end if
end do
end do
!$omp end do
call free_var
!$omp end parallel
end program
【讨论】:
如果我删除schedule
子句,我仍然有一个问题,即在某个时间进度会进入休眠状态。但是如果我加上这个子句,程序会跳转一些循环,比如从j=0到j=6,j=1到5的循环不执行,你知道这是为什么吗?以上是关于并行 fortran 程序将在某个时间休眠的主要内容,如果未能解决你的问题,请参考以下文章
请看看则个fortran结合openmp并行程序,为啥老出错?
开始尝试在 Win7 下使用 OpenMP 编写 fortran 并行程序
openmp+fortran程序,双重do循环外面都加并行,结果好像并行了,但是threadid都是0,请问到底并行没有?