首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >OMP段和DO在同一个并行块中

OMP段和DO在同一个并行块中
EN

Stack Overflow用户
提问于 2016-06-21 16:22:57
回答 2查看 515关注 0票数 0

我有三项任务彼此完全独立,因此是并行执行的好人选:

任务1:执行名为subA()的(单线程)子例程。

任务2:执行名为subB()的(单线程)子例程。

任务3:在DO循环中填充数组。DO-循环的每一次迭代都是独立于所有其他迭代的。

假设我有8个线程。我希望线程0处理任务1,线程1处理任务2,线程2-7处理任务3。

代码语言:javascript
复制
COMPLEX*8, EXTERNAL :: func

!$OMP PARALLEL

!$OMP SECTIONS
!$OMP SECTION
  !
  ! Task 1, performed by one thread
  !
  CALL subA()
!$OMP SECTION
  !
  ! Task 2, performed by one thread
  !
  CALL subB()
!$OMP END SECTIONS NOWAIT

!$OMP DO
  !
  ! Task 3, performed by all threads
  !
  DO j=1,nn             
    vals(j) = func(j)
  END DO
!$OMP END DO NOWAIT

!$OMP END PARALLEL

但是上面的代码不是我想要的。在任务1和任务2上工作的线程也计划在任务3中的DO循环上工作,这似乎减缓了一切,大概是因为这两个线程到达DO循环“晚”了,因此所有其他线程都必须在并行区域末尾的隐式屏障上等待它们。

在这种情况下,处理线程调度的正确方法是什么?

冒着提供太多信息的风险,我已经知道subA()和subB()是计算密集型的,而对func(j)的每个评估都比较快。当多个线程被分配给后一个任务时,完成subA()和subB()所需的时间大致相当于整个DO循环完成所需的时间。

一些注意事项:

  1. 将NUM_THREADS(N)子句添加到"OMP并行“和将NUM_THREADS(N-2)添加到"OMP”中是很有诱惑力的。但我认为"OMP“结构不接受NUM_THREADS子句。
  2. 一种解决方案是在DO循环上使用动态调度。这样,并行DO循环将在线程完成后拾取执行subA()和subB()的线程。这是可行的,但并不令人满意,因为动态调度增加了大量的开销,从而使DO循环的执行时间增加了一个不愉快的量。
  3. 一个相关的问题出现在这里:将多个do-s和节-s置于相同的并行环境中。。然而,对这一问题的答复只确定有可能合并各节,并在相同的并行环境下这样做,但它没有处理我在此提出的日程安排问题。
  4. 我最初是在英特尔的开发者论坛这里上问这个问题的,有人建议我把这个问题跨到堆栈溢出。

ETA:来自英特尔的人指出,我最初的问题是模棱两可的:不清楚我的DO循环是一个memcpy(),从func(1..nn)到vals(1..nn),还是调用一个函数func() nn次。后者是我的意图,我在示例代码中澄清了这一点。

EN

回答 2

Stack Overflow用户

发布于 2016-06-22 13:05:19

使用OpenMP任务,如下所示(未经测试)

代码语言:javascript
复制
!$omp parallel
! Have a single thread create all the tasks. 
!$omp single
!$omp task
   call subA()
!$omp end task
!$omp task
   call subB()
!$omp end task
   DO j=1,nn    
!$omp task         
      vals(j) = func(j)
!$omp end task
   END DO
!$omp end single
!$omp end parallel
票数 0
EN

Stack Overflow用户

发布于 2016-06-22 16:09:14

到目前为止,我找到的最佳解决方案是手动执行我希望OpenMP自动为我执行的调度。特别是,让nthr是我希望使用的线程数。然后,按照以下方式使用SELECT CASE结构:

代码语言:javascript
复制
SELECT CASE (nthr)
CASE (3)
  ! Use 3 threads. See example below
CASE (4)
  ! Use 4 threads. See example below
CASE (5)
  ! And so on...
CASE DEFAULT
  ! Catch-all
END SELECT

在有4个线程的情况下,我执行以下操作:

代码语言:javascript
复制
!$OMP PARALLEL PRIVATE(j) NUM_THREADS(4)
!$OMP SECTIONS
!$OMP SECTION
  !
  ! Task 1, performed by one thread
  !
  CALL subA()

!$OMP SECTION
  !
  ! Task 2, performed by one thread
  !
  CALL subB()

!$OMP SECTION
  !
  ! One thread does half the loop...
  !
  DO j=1,nn/2
    vals(j)=func(j)
  END DO

!$OMP SECTION
  !
  ! ...and one thread does the other half
  !
  DO j=nn/2+1,nn
    vals(j)=func(j)
  END DO

!$OMP END SECTIONS NOWAIT
!$OMP END PARALLEL

nthr的其他值的情况是对上述代码的明显修改。

这个解决方案很好地工作在正确和快速的意义上,但是从软件工程的角度来看,代码重复使得它不太理想。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37949734

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档