taskloop 构造默认有一个隐含的taskgroup 围绕它。考虑到这一点,您的代码会发生什么,single 构造会从并行团队的可用线程中挑选任何一个线程(我将其称为生产者线程)。然后其他 n-1 个线程被直接发送到 single 构造的屏障并等待工作到达(任务)。
现在有了taskgroup,生产者线程开始创建循环任务,然后在taskloop 构造结束时等待所有创建的任务完成:
!$omp parallel
!$omp single
!$omp taskloop num_tasks(10)
DO i=1, 10
A(i) = foo()
END DO
!$omp end taskloop ! producer waits here for all loop tasks to finish
!do other stuff
!$omp taskloop
DO j=1, 10
B(j) = A(j)
END DO
!$omp end taskloop ! producer waits here for all loop tasks to finish
!$omp end single
!$omp end parallel
因此,如果您的并行度(= 第一个 taskloop 创建的任务数)少于屏障中的 n-1 个工作线程,那么其中一些线程将空闲。
如果你想要更多的重叠并且如果“其他东西”独立于第一个taskloop,那么你可以这样做:
!$omp parallel
!$omp single
!$omp taskgroup
!$omp taskloop num_tasks(10) nogroup
DO i=1, 10
A(i) = foo()
END DO
!$omp end taskloop ! producer will not wait for the loop tasks to complete
!do other stuff
!$omp end taskgroup ! wait for the loop tasks (and their descendant tasks)
!$omp taskloop
DO j=1, 10
B(j) = A(j)
END DO
!$omp end taskloop
!$omp end single
!$omp end parallel
唉,从 5.1 版开始的 OpenMP API 不支持 taskloop 构造的任务依赖性,因此您无法轻松描述第一个 taskloop 和第二个 taskloop 的循环迭代之间的依赖性。 OpenMP 语言委员会目前正在着手解决这个问题,但我认为这不是针对 OpenMP API 5.2 版实现的,而是针对 6.0 版实现的。
PS(编辑):对于第二个 taskloop,因为它正好在 single 构造结束之前,因此就在障碍之前,您也可以轻松地在那里添加 nogroup 以避免额外的一点等待生产者线程。