如何突然出现嵌套并行(OpenMP)Fortran循环的惯用方式? [英] How to break out of a nested parallel (OpenMP) Fortran loop idiomatically?

查看:793
本文介绍了如何突然出现嵌套并行(OpenMP)Fortran循环的惯用方式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这里是顺序代码:

  do i = 1,n 
do j = i + 1,n
if(some_condition(i,j))then
result =here's result
return
end if
end do
end do

是否有一种更简洁的方法可以同时执行外循环的迭代:

 !$ OMP PARALLEL private(i,j)
!$ OMP DO
do i = 1,n
! $ OMP FLUSH(找到)
if(found)goto 10
do j = i + 1,n
if(some_condition(i,j))then
!$ OMP CRITICAL
!$ OMP FLUSH(找到)
if(.not.found)然后
found = .true。
result =这是结果
如果
!$ OMP FLUSH(找到)
!$ OMP END CRITICAL
goto 10
如果$ b结束$ b end do
10 continue
end do
!$ OMP END DO NOWAIT
!$ OMP END PARALLEL
$ b

i -loop上的迭代顺序可以是任意的,只要 <找到code> result (只要它满足some_condition),它是否从运行变为运行并不重要) 。

解决方案

似乎 $ OMP DO 不允许出现之前的循环。另一种方法可能是手工实现它。

给每个线程固定连续范围的索引以处理



以下
<$>
p $ p $ results =invalid_value

!$ OMP PARALLEL private(i,j,thread_num,num_threads,start,end)

thread_num = OMP_GET_THREAD_NUM()
num_threads = OMP_GET_NUM_THREADS()
start = thread_num * n / num_threads + 1
end =(thread_num + 1)* n / num_threads

outer如果(发现)退出外部
做j = i + 1,n
if(some_condition):do i = start,end
!$ OMP FLUSH(找到)
那么
found = .true。
!$ OMP FLUSH(找到)
结果(thread_num + 1)=结果如下
退出外部
结束if
结束do
结束do外

!$ OMP END PARALLEL

!如果任何
do i = 1,size(results)
if(results(i).ne。invalid_value)result = results(i)
,则从`results`中提取`result` end do

UPDATE :替换 goto 出口,引入结果基于 @米。 SB的答案

如果存在解决方案,则此方法更快,因此 $ OMP DO

给每个线程一次迭代一次来处理



使用task指令(由<一个href =https://stackoverflow.com/questions/2979760/how-to-break-out-of-a-nested-parallel-openmp-fortran-loop-idiomatically/2983682#2983682> @High Performance Mark ):

 !$ OMP PARALLEL 
!$ OMP SINGLE
!$ OMP TASK UNTIED
! untied允许其他线程产生任务
do i = 1,n!我是私人
!$ OMP任务!暗示冲洗
任务:do j = i + 1,n!我是firstprivate,j是private
if(found)退出任务
if(some_condition(i,j))然后
!$ OMP CRITICAL
result =这里是结果!结果共享
found = .true。 !发现共享
!$ OMP END CRITICAL!暗示刷新
退出任务
结束如果
结束任务
!$ OMP结束任务
结束执行
!$ OMP结束任务
!$ OMP END SINGLE
!$ OMP END PARALLEL

这个变种快了2倍在我的测试中比 outer -loop。


Here's sequential code:

do i = 1, n
   do j = i+1, n
      if ("some_condition(i,j)") then
         result = "here's result"
         return
      end if
   end do
end do

Is there a cleaner way to execute iterations of the outer loop concurrently other than:

  !$OMP PARALLEL private(i,j)
  !$OMP DO 
  do i = 1, n     
     !$OMP FLUSH(found)
     if (found) goto 10
     do j = i+1, n        
        if ("some_condition(i,j)") then
           !$OMP CRITICAL
           !$OMP FLUSH(found)
           if (.not.found) then           
              found = .true.
              result = "here's result"
           end if
           !$OMP FLUSH(found)
           !$OMP END CRITICAL
           goto 10
        end if
     end do
10   continue
  end do
  !$OMP END DO NOWAIT
  !$OMP END PARALLEL

The order of iterations over i-loop may be arbitrary as long as some result is found (it doesn't matter if it changes from run to run as long as it satisfies "some_condition").

解决方案

It seems $OMP DO doesn't allow break out of the loop earlier. An alternative might be to implement it by hand.

Give each thread fixed continuous range of indices to process

Following Guide into OpenMP: Easy multithreading programming for C++:

  results = "invalid_value"

  !$OMP PARALLEL private(i,j,thread_num,num_threads,start,end)

  thread_num = OMP_GET_THREAD_NUM()
  num_threads = OMP_GET_NUM_THREADS()
  start = thread_num * n / num_threads + 1
  end = (thread_num + 1) * n / num_threads

  outer: do i = start, end
     !$OMP FLUSH(found)             
     if (found) exit outer
     do j = i+1, n
        if ("some_condition") then
           found = .true.
           !$OMP FLUSH(found)
           results(thread_num+1) = "here's result"
           exit outer
        end if
     end do
  end do outer

  !$OMP END PARALLEL

  ! extract `result` from `results` if any
  do i = 1, size(results)
     if (results(i).ne."invalid_value") result = results(i)
  end do

UPDATE: replaced goto by exit, introduced results array based on @M. S. B.'s answer.

If solution exists this approach is faster then $OMP DO due to earlier exit.

Give each thread one iteration at a time to process

Using task directive (suggested by @High Performance Mark):

  !$OMP PARALLEL
  !$OMP SINGLE
  !$OMP TASK UNTIED
          ! "untied" allows other threads to generate tasks
  do i = 1, n ! i is private
     !$OMP TASK ! implied "flush"
     task:     do j = i+1, n ! i is firstprivate, j is private       
        if (found) exit task
        if ("some_condition(i,j)") then
           !$OMP CRITICAL
           result = "here's result" ! result is shared              
           found = .true.           ! found is shared
           !$OMP END CRITICAL ! implied "flush"
           exit task
        end if
     end do task
     !$OMP END TASK 
  end do 
  !$OMP END TASK
  !$OMP END SINGLE
  !$OMP END PARALLEL

This variant is 2 times faster on my tests than the version with the outer-loop.

这篇关于如何突然出现嵌套并行(OpenMP)Fortran循环的惯用方式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆