do i=2, n-1
y(i) = y(i+1)
end do
do i=2, n-1
y(i) = y(i+1) - y(i-1)
end do
嗨,我想知道这两个循环是否可以并行化?似乎y(i+1)
部分使其无法实现。因为它取决于尚未生成的价值。
答案 0 :(得分:0)
如果y是一个数组(它看起来像一个函数,但是你将分配给一个函数调用),那么y(i + 1)部分已经存在,尽管它仍然存在问题并行化。
答案 1 :(得分:0)
当然可以。
你只需要以这样一种方式编写它,即每个并行任务都不会“踩到”任何其他任务的内存。
在第二种情况下,这将是一个棘手的问题,但我确信这可能有足够的想法。
答案 2 :(得分:0)
在第一种情况下,只有拥有辅助存储区域时才能进行并行化。为了获得最大的并行性,您需要一个完全独立的数组:
for all i in [2, n-2] in parallel do
y'(i) = y(i+1)
end do
如果您只想使用两个并行执行单元,则需要存储阵列的一个元素:
e = y(n/2)
for all i in [0, 1] in parallel do
for j in [1, n/2 - 1] do
y(i*n/2 + j) = (y(i*n/2 + j)
end do
end do
y(n/2 - 1) = e
你需要这个来避免前半部分的最后一个元素和后半部分的第一个元素的竞争条件。实际上,您需要的额外存储量与并行化代码的因素之间存在直接关系。
第二个循环不能并行化,因为你必须计算y(i-1)来计算y(i)。没门。这对于第一个循环来说不是问题,因为在循环开始之前,所有最终读取的值都保证在它们中具有正确的值。第二次不是这样!
对于它的价值,这些循环可以组合,如果它们是要按顺序执行的话。这比并行化第一个并且仅剩下第二个更快。
答案 3 :(得分:0)
在这两种情况下,你都拥有所谓的“循环携带依赖”
do i=2, n-1
y(i) = y(i+1) - y(i-1)
end do
y(i)的计算取决于y(i +/- 1),因为在并行循环中你不能保证执行i的顺序y(i + 1)可能已经更新为新的计算y(i)之前的值。更糟糕的是y(i + 1)可能正在一个线程上更新,而另一个线程试图读取可能是一个损坏的值(因为它的数据只是更新的一半。在任何一种情况下你都会得到不正确的答案。
这里最好的解决方案是拥有一个只读和可写的数组
do i=2, n-1
yNew(i) = yOld(i+1) - yOld(i-1)
end do
swap(yOld, yNew)
现在你的问题消失了,因为并行循环不会更新数组y。如果您的语言支持指针,您可以通过维护指向它们的指针并简单地交换指针来轻松交换新/旧数组。唯一的额外开销是您需要将数据的附加副本作为循环的只读副本进行引用。