Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/161.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ tbb::parallel_reduce vs tbb::combinable vs tbb::enumerable_thread_specific_C++_Multithreading_Image Processing_Tbb_Eigen3 - Fatal编程技术网

C++ tbb::parallel_reduce vs tbb::combinable vs tbb::enumerable_thread_specific

C++ tbb::parallel_reduce vs tbb::combinable vs tbb::enumerable_thread_specific,c++,multithreading,image-processing,tbb,eigen3,C++,Multithreading,Image Processing,Tbb,Eigen3,我想通过一个图像,处理一些与元素的顺序有关的特定值。图像有一个无符号字符*数组,其中包含一个掩码(如果要处理像素,则为255,否则为0)和一个无符号短字符*数组,其中包含像素值 我用tbb实现了三种不同的方法,并通过掩码数组使用了一个for循环,并从循环变量计算了x,y坐标:x=I%width;y=i/宽度。如果像素可见,我想使用Eigen变换点。 vector4d是存储点的std::vector 以下是我对tbb的三个实现: 1tbb::可组合的和tbb::并行的: void Combinab

我想通过一个图像,处理一些与元素的顺序有关的特定值。图像有一个
无符号字符*
数组,其中包含一个掩码(如果要处理像素,则为255,否则为0)和一个
无符号短字符*
数组,其中包含像素值

我用tbb实现了三种不同的方法,并通过掩码数组使用了一个for循环,并从循环变量计算了x,y坐标:
x=I%width;y=i/宽度。如果像素可见,我想使用
Eigen
变换点。
vector4d
是存储点的
std::vector

以下是我对tbb的三个实现:

1
tbb::可组合的
tbb::并行的:

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;
    });
}
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;
    });
}
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;
        }
    );  
}
3<代码>tbb::并行减少:

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;
    });
}
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;
    });
}
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;
        }
    );  
}
void Reduce(整数宽度、整数高度、无符号字符*掩码、无符号短*像素){
vector4d idx=tbb::parallel_reduce(
tbb::分块_范围(0,宽度*高度),矢量4d(),
[&](常量tbb::阻塞的范围&r,向量4D初始化)->vector4d
{
const size_t end=r.end();
初始储备(r.size());
for(int i=r.begin();i!=end;++i)
{   
如果(掩码[i]!=0)
{               
array4d arr={i%宽度,i/宽度,(双)像素[i],1};
//本征映射与变换
初始推回(arr);
}
}
返回init;
},
[](向量4d x,向量4d y)
{
std::size_t n=x.size();
x、 调整大小(n+y.size());
std::move(y.begin(),y.end(),x.begin()+n);
返回x;
}
);  
}
我将三个版本的运行时与串行实现进行了比较。阵列有8400000个元素,每个算法重复100次。结果是:

  • 序列号:~170ms
  • 可枚举:~118ms
  • 可组合:~116ms
  • 减少:~720ms

我假设
combine
语句是这里的瓶颈。我做错了什么?为什么
parallel\u reduce
soo要慢得多?请帮忙

这里可以应用的优化很少

  • 避免过度复制:传递
    const vector4d&
    ,在任何地方使用
    [&]
    lambdas
  • 在堆栈上使用临时
    vector4d
    ,而不是调整其中一个参数的大小,并将其用于return语句
  • 通常,使用
    blocked_range2d
    代替计算
    x=i%宽度;y=i/宽度
    。这不仅优化了过多的计算,而且更重要的是,它优化了可能提高缓存使用率的缓存访问模式(但在本例中不是这样)

  • 如果您使用的是parallel_reduce的函数形式,请尝试更有效的命令式形式。很遗憾,不能使用lambdas调用它,必须定义一个Body类:

    它应该最大限度地减少在缩减过程中生成的vector4d拷贝数。vector4d应该是Body类的一个成员,这样它就可以被多个范围重用和附加,而不是为每个细分的范围构造和合并一个唯一的vector4d


    (注意:拆分构造函数不应复制vector4d成员的内容,请注意,在上面的英特尔示例中,
    value
    始终初始化为0。)

    您正在按值将
    vector4d
    传递给lambda表达式。
    vector4d
    的复制构造函数有多贵?我更新了我的问题。我完全忘了提vector4d,谢谢你的提示!请参阅下面我的更好答案,但对代码的一个小改进是:
    init.reserve(init.size()+r.size())