Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance 使用OpenMP并行Fortran中的分支递归子例程时线程创建失败_Performance_Recursion_Parallel Processing_Fortran_Openmp - Fatal编程技术网

Performance 使用OpenMP并行Fortran中的分支递归子例程时线程创建失败

Performance 使用OpenMP并行Fortran中的分支递归子例程时线程创建失败,performance,recursion,parallel-processing,fortran,openmp,Performance,Recursion,Parallel Processing,Fortran,Openmp,我正在用Fortran编写一个递归子例程,它扩展为二叉树(即,该过程调用自身两次,直到到达分支的末尾)。一般算法逻辑为: ''' ''' 原则上,这可以通过并行计算大大加速,但是,当我使用OpenMP并行化循环时,运行产生的可执行文件时会出现以下错误: libgomp:线程创建失败:资源暂时不可用线程创建失败:资源暂时不可用 我猜堆栈的大小太大了,但我还没有找到解决方案或解决方法。我有没有办法使用并行计算来提高这种算法的性能 -OpenMP或gfortran是否有帮助避免这些问题的选项 -只在树

我正在用Fortran编写一个递归子例程,它扩展为二叉树(即,该过程调用自身两次,直到到达分支的末尾)。一般算法逻辑为:

'''

'''

原则上,这可以通过并行计算大大加速,但是,当我使用OpenMP并行化循环时,运行产生的可执行文件时会出现以下错误:

libgomp:线程创建失败:资源暂时不可用线程创建失败:资源暂时不可用

我猜堆栈的大小太大了,但我还没有找到解决方案或解决方法。我有没有办法使用并行计算来提高这种算法的性能

-OpenMP或gfortran是否有帮助避免这些问题的选项

-只在树中某个级别的上方或下方进行并行化是否有帮助

—C或C++是这个应用的更好选择吗?< /P> 我正在为macOS Catalina工作。堆栈大小硬限制为65532。 我的环境变量是:

OMP_嵌套=真


OMP_DYNAMIC=True

这听起来更像是您的代码由于非常深的递归而创建了太多线程。有很多方法可以缓解这种情况。例如,OpenMP 4.5引入了由(内部控制变量)控制的最大活动级别的概念。您可以通过设置
OMP\u MAX\u ACTIVE\u LEVELS
环境变量或调用
OMP\u set\u MAX\u ACTIVE\u LEVELS()
来设置其值。一旦嵌套级别达到max active levels var指定的级别,嵌套得更深的并行区域将被停用,即,它们将按顺序执行,而不会产生新线程

如果您的编译器不支持OpenMP 4.5,或者您希望您的代码与旧的编译器向后兼容,那么您可以通过跟踪嵌套级别并禁用并行区域来手动执行此操作。对于后者,有
if(b)
子句,当应用于并行区域时,仅当
b
的计算结果为
.true.
时,该子句才使其处于活动状态。代码的并行实现示例:

subroute my_subroutine(inputs, output, level)
  use input to generate possible new_input(:,1) and new_input(:,2)
!$omp parallel do schedule(static,1) if(level<max_levels)
  do i=1,2
    call my_subroutine(new_input(:,i), new_output(i), level+1)
  enddo
!$omp end parallel do
  output = best(new_output(1), new_output(2))
end subroutine my_subroutine
在这里,循环的每次迭代都成为一个单独的任务。如果已达到嵌套的
max_levels
,则任务将成为最终任务,这意味着它们不会被延迟(即,将按顺序执行),并且每个嵌套任务也将是最终任务,从而有效地停止递归树下的并行执行。任务循环是OpenMP 4.5中引入的一项方便功能。对于早期的编译器,可以使用以下等效代码:

subroutine my_subroutine(inputs, output, level)
  use input to generate possible new_input(:,1) and new_input(:,2)
  do i=1,2
!$omp task shared(new_input, new_output) final(level>=max_levels)
    call my_subroutine(new_input(:,i), new_output(i), level+1)
!$omp end task
  end do
!$omp taskwait
  output = best(new_output(1), new_output(2))
end subroutine my_subroutine
任务代码中没有并行的结构。相反,您需要从并行区域内调用
my_子例程
,惯用的方法是这样做:

!$omp parallel
!$omp single
  call my_subroutine(inputs, output, 0)
!$omp end single
!$omp end parallel

嵌套并行版本和使用任务的版本之间有一个根本的区别。在前一种情况下,在每个递归级别,当前线程分成两个分支,每个线程并行执行一半的计算。这里需要限制活动并行级别,以防止运行时产生过多线程并耗尽系统资源。在后一种情况下,在每个递归级别创建两个新任务,并推迟到以后,可能由与并行区域关联的线程团队并行执行。线程的数量保持不变,这里的限制限制了任务开销的增加,这比生成新的并行区域的开销小得多。因此,任务代码的
max_levels
最佳值将与嵌套并行代码的最佳值显著不同。

这听起来更像是由于非常深的递归,您的代码创建了太多线程。有很多方法可以缓解这种情况。例如,OpenMP 4.5引入了由(内部控制变量)控制的最大活动级别的概念。您可以通过设置
OMP\u MAX\u ACTIVE\u LEVELS
环境变量或调用
OMP\u set\u MAX\u ACTIVE\u LEVELS()
来设置其值。一旦嵌套级别达到max active levels var指定的级别,嵌套得更深的并行区域将被停用,即,它们将按顺序执行,而不会产生新线程

如果您的编译器不支持OpenMP 4.5,或者您希望您的代码与旧的编译器向后兼容,那么您可以通过跟踪嵌套级别并禁用并行区域来手动执行此操作。对于后者,有
if(b)
子句,当应用于并行区域时,仅当
b
的计算结果为
.true.
时,该子句才使其处于活动状态。代码的并行实现示例:

subroute my_subroutine(inputs, output, level)
  use input to generate possible new_input(:,1) and new_input(:,2)
!$omp parallel do schedule(static,1) if(level<max_levels)
  do i=1,2
    call my_subroutine(new_input(:,i), new_output(i), level+1)
  enddo
!$omp end parallel do
  output = best(new_output(1), new_output(2))
end subroutine my_subroutine
在这里,循环的每次迭代都成为一个单独的任务。如果已达到嵌套的
max_levels
,则任务将成为最终任务,这意味着它们不会被延迟(即,将按顺序执行),并且每个嵌套任务也将是最终任务,从而有效地停止递归树下的并行执行。任务循环是OpenMP 4.5中引入的一项方便功能。对于早期的编译器,可以使用以下等效代码:

subroutine my_subroutine(inputs, output, level)
  use input to generate possible new_input(:,1) and new_input(:,2)
  do i=1,2
!$omp task shared(new_input, new_output) final(level>=max_levels)
    call my_subroutine(new_input(:,i), new_output(i), level+1)
!$omp end task
  end do
!$omp taskwait
  output = best(new_output(1), new_output(2))
end subroutine my_subroutine
任务代码中没有并行的结构。相反,您需要从并行区域内调用
my_子例程
,惯用的方法是这样做:

!$omp parallel
!$omp single
  call my_subroutine(inputs, output, 0)
!$omp end single
!$omp end parallel
嵌套并行版本和使用任务的版本之间有一个根本的区别。在前一种情况下,在每个递归级别,当前线程分成两个分支,每个线程并行执行一半的计算。这里需要限制活动并行级别,以防止运行时产生过多线程并耗尽系统资源。在后一种情况下,在每个递归级别创建两个新任务,并将其延迟到la