如何突然出现嵌套并行(OpenMP)Fortran循环的惯用方式? [英] How to break out of a nested parallel (OpenMP) Fortran loop idiomatically?
问题描述
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
不允许出现之前的循环。另一种方法可能是手工实现它。
给每个线程固定连续范围的索引以处理
以下 UPDATE :替换 如果存在解决方案,则此方法更快,因此 使用task指令(由<一个href =https://stackoverflow.com/questions/2979760/how-to-break-out-of-a-nested-parallel-openmp-fortran-loop-idiomatically/2983682#2983682> @High Performance Mark
<$> 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
goto
出口,引入结果
基于 @米。 SB的答案。
$ OMP DO
给每个线程一次迭代一次来处理
!$ 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屋!