构建分组数据结构with/for TBB
Constructing a grouped data structure with/for TBB
最近我一直在考虑使用 TBB 而不是 boost.threads 来加快开发速度。通常 parallel_for 在大多数情况下都有效,但我这里的情况有点复杂。
有一个需要计算的结构数组,已根据成员变量排序。这是因为变量值与将在计算期间访问的数据相关,并且根据此对结构进行分组将允许串行设计中的缓存一致性。
#include <tbb/tbb.h>
#include <iostream>
struct thing
{
float value_one;
float value_two;
unsigned int sort_id;
};
class functor
{
thing* m_array;
public:
functor(thing* _array) : m_array(_array) {;}
void operator()(const tbb::blocked_range<unsigned int>& r) const
{
for(int i = r.begin(); i != r.end(); ++i)
{
//Doing a computation with array
m_array[i].value_one = m_array[i].value_two * m_array[i].value_two;
}
}
};
int main(int argc, char const *argv[])
{
unsigned int n = 10;
thing* array = new thing[n];
// Note the ordered id groups
array[0].sort_id = 1;
array[1].sort_id = 1;
array[2].sort_id = 1;
array[3].sort_id = 2;
array[4].sort_id = 3;
array[5].sort_id = 5;
array[6].sort_id = 5;
array[7].sort_id = 9;
array[8].sort_id = 9;
array[9].sort_id = 9;
// Do something parallel with array here...
// parallel_for(tbb::blocked_range<unsigned int>(0, n, 2), functor(array));
delete[] array;
return 0;
}
上面给出了一个简化的例子,但实际上我很可能会有一个包含大约 30-60 百万个元素的数组。
我理解 parallel_for 会将数组划分为分组范围。但是我希望每个范围都包含特定 id 的所有结构。我不介意该范围是否包含多个 ID 的结构,只要它们是连续的并且包含这两个 ID 的所有结构。
int count = 0;
thing** blocks = new thing*[7];
int* sizes = new int[7];
int current_id = 0;
for(unsigned int i = 0; i < n; ++i)
{
if(array[i].sort_id != current_id)
{
current_id = array[i].sort_id;
blocks[count] = &array[i];
sizes[count] = 1;
++count;
}
else
{
sizes[count - 1] += 1;
}
}
parallel_for(tbb::blocked_range<unsigned int>(0, count, 2), functor(blocks, sizes));
我是否应该以某种方式将数组分成由另一个数组指向的较小块,然后将其并行化(如上面的代码所示),如果是这样,执行此操作的有效方法是什么,或者给出的示例是什么最佳的?有没有 parallel_for 的替代方案(例如 task_group)更适合这个问题?
这个问题对我来说还不是很清楚,因为你混合了目标和可能的方法。
如果需要对数组进行排序,则有parallel_sort
如果您需要为排序数组建立索引,其中 sort_id
作为键映射到给定元素组驻留在主数组中的索引,请使用 concurrent_unordered_map
存储组(如果有大量组)并使用 parallel_for
来构建它。
如果组数少于数百个,可以使用std::map
或std::unordered_map
并使用parallel_reduce
构建部分地图并将它们合并到最终状态。
最后,当您拥有正确的组数据结构时,您可以根据需要跨组使用 parallel_for
。
P.S。这个:
grouped ranges called tasks that will be added to the stack for computation
我听起来真的很奇怪。有一个用户函子(或 C++11 lambda), 可以 并行调用以处理不同的范围 [begin;end)
。如果你把函子叫做'task',没关系,但不要把它和tbb::task
.
混在一起
最近我一直在考虑使用 TBB 而不是 boost.threads 来加快开发速度。通常 parallel_for 在大多数情况下都有效,但我这里的情况有点复杂。
有一个需要计算的结构数组,已根据成员变量排序。这是因为变量值与将在计算期间访问的数据相关,并且根据此对结构进行分组将允许串行设计中的缓存一致性。
#include <tbb/tbb.h>
#include <iostream>
struct thing
{
float value_one;
float value_two;
unsigned int sort_id;
};
class functor
{
thing* m_array;
public:
functor(thing* _array) : m_array(_array) {;}
void operator()(const tbb::blocked_range<unsigned int>& r) const
{
for(int i = r.begin(); i != r.end(); ++i)
{
//Doing a computation with array
m_array[i].value_one = m_array[i].value_two * m_array[i].value_two;
}
}
};
int main(int argc, char const *argv[])
{
unsigned int n = 10;
thing* array = new thing[n];
// Note the ordered id groups
array[0].sort_id = 1;
array[1].sort_id = 1;
array[2].sort_id = 1;
array[3].sort_id = 2;
array[4].sort_id = 3;
array[5].sort_id = 5;
array[6].sort_id = 5;
array[7].sort_id = 9;
array[8].sort_id = 9;
array[9].sort_id = 9;
// Do something parallel with array here...
// parallel_for(tbb::blocked_range<unsigned int>(0, n, 2), functor(array));
delete[] array;
return 0;
}
上面给出了一个简化的例子,但实际上我很可能会有一个包含大约 30-60 百万个元素的数组。
我理解 parallel_for 会将数组划分为分组范围。但是我希望每个范围都包含特定 id 的所有结构。我不介意该范围是否包含多个 ID 的结构,只要它们是连续的并且包含这两个 ID 的所有结构。
int count = 0;
thing** blocks = new thing*[7];
int* sizes = new int[7];
int current_id = 0;
for(unsigned int i = 0; i < n; ++i)
{
if(array[i].sort_id != current_id)
{
current_id = array[i].sort_id;
blocks[count] = &array[i];
sizes[count] = 1;
++count;
}
else
{
sizes[count - 1] += 1;
}
}
parallel_for(tbb::blocked_range<unsigned int>(0, count, 2), functor(blocks, sizes));
我是否应该以某种方式将数组分成由另一个数组指向的较小块,然后将其并行化(如上面的代码所示),如果是这样,执行此操作的有效方法是什么,或者给出的示例是什么最佳的?有没有 parallel_for 的替代方案(例如 task_group)更适合这个问题?
这个问题对我来说还不是很清楚,因为你混合了目标和可能的方法。
如果需要对数组进行排序,则有parallel_sort
如果您需要为排序数组建立索引,其中 sort_id
作为键映射到给定元素组驻留在主数组中的索引,请使用 concurrent_unordered_map
存储组(如果有大量组)并使用 parallel_for
来构建它。
如果组数少于数百个,可以使用std::map
或std::unordered_map
并使用parallel_reduce
构建部分地图并将它们合并到最终状态。
最后,当您拥有正确的组数据结构时,您可以根据需要跨组使用 parallel_for
。
P.S。这个:
grouped ranges called tasks that will be added to the stack for computation
我听起来真的很奇怪。有一个用户函子(或 C++11 lambda), 可以 并行调用以处理不同的范围 [begin;end)
。如果你把函子叫做'task',没关系,但不要把它和tbb::task
.