[英]OpenMP parallelization on a recursive function
我正在尝试使用并行化来提高绘制具有层次排序对象的3D场景的刷新率。 场景绘制算法首先递归地遍历对象树,并从中构建绘制场景所需的有序数据的有序数组。 然后它多次遍历该数组以绘制对象/覆盖等。从我读到的OpenGL不是一个线程安全的API,我假设数组遍历/绘图代码必须在主线程上完成,但我我想我可能能够并行化填充数组的递归函数。 关键问题是必须按照对象在场景中出现的顺序填充数组,因此所有将给定对象与数组索引相关联的功能必须按正确的顺序完成,但是一旦分配了数组索引,我可以使用工作线程填充该数组元素的数据(这不一定是一个简单的操作)。 所以这是我想要的伪代码。 我希望你能理解xml-ish线程的语法。
recursivepopulatearray(theobject)
{
<main thread>
for each child of theobject
{
assign array index
<child thread(s)>
populate array element for child object
</child thread(s)>
recursivepopulatearray(childobject)
}
</main thread>
}
那么,是否可以使用OpenMP执行此操作,如果是这样,怎么做? 是否有其他并行化库可以更好地处理这个问题?
附录:为了回应Davide要求进一步澄清的请求 ,让我详细解释一下。 让我们说场景是这样排序的:
-Bicycle Frame
- Handle Bars
- Front Wheel
- Back Wheel
-Car Frame
- Front Left Wheel
- Front Right Wheel
- Back Left Wheel
- Back Right Wheel
现在,这些对象中的每一个都有很多与之相关的数据,即位置,旋转,大小,不同的绘图参数等。另外,我需要在这个场景上进行多次传递才能正确绘制它。 一个通道绘制对象的形状,另一个通道绘制描述对象的文本,另一个通道绘制对象之间的连接/关联(如果有)。 无论如何,如果我必须多次访问它,从这些不同的对象中获取所有绘图数据是相当慢的,所以我决定使用一个通道将所有数据缓存到一维数组中,然后实际所有绘图传递只看数组。 问题在于,因为我需要以正确的顺序进行OpenGL推送/弹出,所以数组必须处于代表树层次结构的正确深度优先搜索顺序中。 在上面的示例中,必须按如下方式对数组进行排序:
index 0: Bicycle Frame
index 1: Handle Bars
index 2: Front Wheel
index 3: Back Wheel
index 4: Car Frame
index 5: Front Left Wheel
index 6: Front Right Wheel
index 7: Back Left Wheel
index 8: Back Right Wheel
因此,必须正确地序列化数组的顺序,但是一旦我正确地分配了该顺序,我就可以并行化数组的填充。 例如,一旦我将自行车框架分配给索引0并将把手杆分配给索引1,一个线程可以为自行车框架填充数组元素,而另一个线程则为句柄条填充数组元素。
好吧,我想澄清这一点,我已经回答了我自己的问题,所以感谢Davide。 所以我发布了自己的答案 。
我认为你应该更好地澄清你的问题(例如,什么必须连续完成,为什么)
OpenMP的(像其他许多并行库)并不能保证在不同的并行部分将被执行的顺序,因为他们是真正的并行(多核计算机上),如果不同的部分写相同的数据可能存在竞争条件。 如果你的问题没问题,你肯定可以使用它。
正如gbjbaanb所提到的 ,你可以很容易地做到这一点 - 它只需要一个pragma语句来并行化它。
但是,有几点需要注意:
首先,你提到这里的订单很重要。 如果您需要在展平层次结构时保留排序,那么并行化(在此级别)将会出现问题。 你可能会完全失去你的订单。
此外,并行化递归函数存在许多问题。 举一个极端的情况 - 假设你有一个双核机器,你有一棵树,每个“父”节点有4个孩子。 如果树很深,你会非常非常快地“过度并行化”这个问题,通常会使事情变得更糟,而不是更好,性能更好。
如果您要这样做,您应该放置一个级别参数,并且只能并行化前几个级别。 以我的4个孩子每个父母为例,如果你并行化前两个级别,你已经将它分成16个并行块(从4个并行块调用)。
从你提到的,我将这部分串行,而不是你提到的第二部分:
“然后它遍历该数组多次绘制对象/叠加等。”
这听起来像是一个理想的并行化地方。
要并行化子线程,只需在循环之前放置一个pragma:
#pragma omp parallel for
for (i=0; i < elements; i++)
{
}
任务完成。
现在,你是对的,你不能让任何线程库以完全并行的方式在另一个之前做一点(显然!),而openMP没有'lock'或'wait'功能(它确实有''等待所有人完成“关键字 - 屏障”,它不是为了模拟一个线程库而设计的,但它确实允许你在并行部分“外部”存储值,并将某些部分标记为“仅单线程”(有序关键字)所以这可以帮助您在并行循环中分配索引,而其他线程正在分配元素。
看一下入门指南 。
如果您使用的是Visual C ++,则还需要在编译器构建设置中设置/ omp标志。
这是一段应该有效的修改过的伪代码。
populatearray(thescene)
{
recursivepopulatearray(thescene)
#pragma omp parallel for
for each element in array
populate array element based on associated object
}
recursivepopulatearray(theobject)
{
for each childobject in theobject
{
assign array index and associate element with childobject
recursivepopulatearray(childobject)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.