【发布时间】:2016-08-22 15:09:55
【问题描述】:
我想浏览一张图片并处理一些关于元素顺序的特定值。该图像有一个 unsigned char* 数组,其中包含一个掩码(如果应处理像素,则为 255,否则为 0)和一个包含像素值的 unsigned short* 数组。
我用 tbb 实现了三种不同的方法,并在掩码数组中使用了一个 for 循环,并从循环变量中计算了 x,y 坐标:x = i%width; y = i/width;。如果像素可见,我想使用Eigen 转换点。
vector4d 是一个 std::vector<std::array<double,4>> 来存储积分。
这是我使用 tbb 的三个实现:
1. tbb::combinable 和 tbb::parallel_for :
void Combinable(int width, int height, unsigned char* mask,unsigned short* pixel){
MyCombinableType.clear();
MyCombinableType.local().reserve(width*height);
tbb::parallel_for( tbb::blocked_range<int>(0, width*height),
[&](const tbb::blocked_range<int> &r)
{
vector4d& local = MyCombinableType.local();
const size_t end = r.end();
for (int i = r.begin(); i != end; ++i)
{
if(mask[i]!=0)
{
array4d arr = {i%width,i/width,(double)pixel[i],1};
//Map with Eigen and transform
local.push_back(arr);
}
}
});
vector4d idx = MyCombinableType.combine(
[]( vector4d x, vector4d y)
{
std::size_t n = x.size();
x.resize(n + y.size());
std::move(y.begin(), y.end(), x.begin() + n);
return x;
});
}
2。 tbb::enumerable_thread_specific 和 tbb::parallel_for:
void Enumerable(int width, int height, unsigned char* mask,unsigned short* pixel){
MyEnumerableType.clear();
MyEnumerableType.local().reserve(width*height);
tbb::parallel_for( tbb::blocked_range<int>(0, width*height),
[&](const tbb::blocked_range<int> &r)
{
enumerableType::reference local = MyEnumerableType.local();
for (int i = r.begin(); i != r.end(); ++i)
{
if(mask[i]!=0)
{
array4d arr = {i%width,i/width,(double)pixel[i],1};
//Map with Eigen and transform
local.push_back(arr);
}
}
});
vector4d idx = MyEnumerableType.combine(
[](vector4d x, vector4d y)
{
std::size_t n = x.size();
x.resize(n + y.size());
std::move(y.begin(), y.end(), x.begin() + n);
return x;
});
}
3. tbb::parallel_reduce:
void Reduce(int width, int height, unsigned char* mask,unsigned short* pixel){
vector4d idx = tbb::parallel_reduce(
tbb::blocked_range<int>(0, width*height ),vector4d(),
[&](const tbb::blocked_range<int>& r, vector4d init)->vector4d
{
const size_t end = r.end();
init.reserve(r.size());
for( int i=r.begin(); i!=end; ++i )
{
if(mask[i]!=0)
{
array4d arr = {i%width,i/width,(double)pixel[i],1};
//Map with Eigen and transform
init.push_back(arr);
}
}
return init;
},
[]( vector4d x,vector4d y )
{
std::size_t n = x.size();
x.resize(n + y.size());
std::move(y.begin(), y.end(), x.begin() + n);
return x;
}
);
}
我将三个版本的运行时间与串行实现进行了比较。数组有 8400000 个元素,每个算法重复 100 次。结果是:
- 串行:~170ms
- 可枚举:~118ms
- 可组合:~116ms
- 减少:~720ms
我假设combine 语句是这里的瓶颈。我究竟做错了什么?为什么parallel_reduce 这么慢?请帮忙!
【问题讨论】:
-
您将
vector4d按值传递给 lambda 表达式。vector4d的复制构造函数有多贵? -
我更新了我的问题。我完全忘了提到vector4d,谢谢你的提示!
-
在下面查看我更好的答案,但对您的代码的小改进是:
init.reserve(init.size() + r.size());
标签: c++ multithreading image-processing tbb eigen3