OpenMP 任务循环:两个连续任务循环构造之间的同步
OpenMP taskloop: synchronization between two consecutive taskloop constructs
两个 taskloop
构造之间的同步是如何完成的?具体来说,在下面的伪代码中,如果可用线程数多于第一个循环的任务数,我相信这些空闲线程在单个构造结束时的隐式屏障处旋转。现在是否允许这些空闲线程同时开始执行第二个循环,从而使以这种方式并行化事物变得不安全(由于数组 A
的相互依赖性)?
!$omp parallel
!$omp single
!$omp taskloop num_tasks(10)
DO i=1, 10
A(i) = foo()
END DO
!$omp end taskloop
!do other stuff
!$omp taskloop
DO j=1, 10
B(j) = A(j)
END DO
!$omp end taskloop
!$omp end single
!$omp end parallel
我没能从API规范中找到明确的答案:https://www.openmp.org/spec-html/5.0/openmpsu47.html#x71-2080002.10.2
默认情况下,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
也可以避免等待生产者线程的额外时间。
两个 taskloop
构造之间的同步是如何完成的?具体来说,在下面的伪代码中,如果可用线程数多于第一个循环的任务数,我相信这些空闲线程在单个构造结束时的隐式屏障处旋转。现在是否允许这些空闲线程同时开始执行第二个循环,从而使以这种方式并行化事物变得不安全(由于数组 A
的相互依赖性)?
!$omp parallel
!$omp single
!$omp taskloop num_tasks(10)
DO i=1, 10
A(i) = foo()
END DO
!$omp end taskloop
!do other stuff
!$omp taskloop
DO j=1, 10
B(j) = A(j)
END DO
!$omp end taskloop
!$omp end single
!$omp end parallel
我没能从API规范中找到明确的答案:https://www.openmp.org/spec-html/5.0/openmpsu47.html#x71-2080002.10.2
默认情况下,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
也可以避免等待生产者线程的额外时间。