TBB并行编程_4分治,流水线

这是一个很基础的计算斐波那契额数列的算法,用递归实现的: 

int fib(int n) {
    if (n < 2)
        return n;
    int first = fib(n - 1);
    int second = fib(n - 2);
    return first + second;
}

int main() {
    TICK(fib);
    std::cout << fib(39) << std::endl;
    TOCK(fib);
    return 0;
}

 在这里分别使用了两种算法,第一种是串行的,第二种是cut-off并行的(就是当数据较小的时候采用串行,数据较大的地方采用并行)。

封装好的排序库:tbb::parallel_sort

int main() {
	size_t n = 1 << 20;
	std::vector<int> arr(n);
	std::generate(arr.begin(), arr.end(), std::rand);
	TICK(sort);
	/*std::cout << serial_fib(39) << std::endl;*/
	tbb::parallel_sort(arr.begin(), arr.end(), std::less<int>{});
	TOCK(sort);
	return 0;
}

 流水线并行:

 加入要对上面的数据进行并行操作,可能一下子就会想到parallel_for_each这种简单粗暴的方法。

但这种加速效果并不是很好,这是因为循环体太大,每跑一遍都要重置指令缓存和数据缓存。而且每个核心都在读写不同地方的数据,导致内存瓶颈,效果很不好。

tbb采用了一种流水线并行的策略:tbb::parallel_pipeline

 像是这一种,那么在这里当t4处理d1的s4的时候,t3正在处理d2的s3。

#include <iostream>
#include <cstdlib>
#include <vector>
#include <cmath>
#include <numeric>
#include "ticktock.h"
#include <tbb/parallel_pipeline.h>

struct Data {
    std::vector<float> arr;

    Data() {
        arr.resize(std::rand() % 100 * 500 + 10000);
        for (int i = 0; i < arr.size(); i++) {
            arr[i] = std::rand() * (1.f / (float)RAND_MAX);
        }
    }

    void step1() {
        for (int i = 0; i < arr.size(); i++) {
            arr[i] += 3.14f;
        }
    }

    void step2() {
        std::vector<float> tmp(arr.size());
        for (int i = 1; i < arr.size() - 1; i++) {
            tmp[i] = arr[i - 1] + arr[i] + arr[i + 1];
        }
        std::swap(tmp, arr);
    }

    void step3() {
        for (int i = 0; i < arr.size(); i++) {
            arr[i] = std::sqrt(std::abs(arr[i]));
        }
    }

    void step4() {
        std::vector<float> tmp(arr.size());
        for (int i = 1; i < arr.size() - 1; i++) {
            tmp[i] = arr[i - 1] - 2 * arr[i] + arr[i + 1];
        }
        std::swap(tmp, arr);
    }
};

int main() {
    size_t n = 1 << 11;
    std::vector<Data> dats(n);
    std::vector<float> result;
    TICK(process);
    auto it = dats.begin();
    tbb::parallel_pipeline(8,
        tbb::make_filter<void, Data*>(tbb::filter_mode::serial_in_order, [&](tbb::flow_control& fc)->Data* {
        if (it == dats.end()){
            fc.stop();
            return nullptr;
        }
        return &*it++;
        }),
        tbb::make_filter<Data*, Data*>(tbb::filter_mode::parallel, [&](Data* dat) -> Data* {
            
                dat->step1();
                return dat;
        }),
        tbb::make_filter<Data*, Data*>(tbb::filter_mode::parallel, [&](Data* dat) -> Data* {
            
                dat->step2();
                return dat;
        }),
        tbb::make_filter<Data*, Data*>(tbb::filter_mode::parallel, [&](Data* dat) -> Data* {
            
                dat->step3();
                return dat;
        }), 
        
        tbb::make_filter<Data*, float>(tbb::filter_mode::parallel,[&](Data* dat) -> float {
                float sum = std::reduce(dat->arr.begin(), dat->arr.end());
                return sum;
        }), 
        tbb::make_filter<float, void>(tbb::filter_mode::serial_out_of_order,[&](float sum) -> void {
                result.push_back(sum);
        })
        );

    TOCK(process);

    return 0;
}


tbb::make_filter<void, Data *>(tbb::filter_mode::serial_in_order, ...):这是一个函数调用,用于创建一个过滤器。它指定了过滤器的输入类型为void,表示没有输入数据,输出类型为Data*,表示输出为指向Data类型对象的指针。tbb::filter_mode::serial_in_order表示过滤器以串行顺序的方式执行。

[&] (tbb::flow_control &fc) -> Data * {:这是一个lambda表达式,定义了过滤器的功能。[&]表示使用lambda表达式中可见的所有变量(包括引用)。

if (it == dats.end()) {:这是一个条件语句,用于检查是否遍历完数据。it是一个迭代器,指向dats容器的当前元素。dats.end()是dats容器的结束迭代器,用于表示遍历结束。如果it等于dats.end(),即已经遍历完数据,则执行下面的代码块。

fc.stop();:这是一个流程控制函数,用于停止管道的执行。当遍历完数据时,调用fc.stop()停止后续过滤器的执行。

return nullptr;:如果遍历完数据,返回nullptr表示没有输出数据。

return &*it++;:如果尚未遍历完数据,执行这行代码。*it表示迭代器it指向的当前元素,it++将迭代器向前移动一位。&*it表示当前元素的地址,即指向Data类型对象的指针。该指针将作为过滤器的输出数据。

这段代码的功能是在并行管道中依次遍历dats容器的元素,并将每个元素作为输出数据传递给下一个过滤器。当遍历完所有元素时,通过调用fc.stop()停止管道的执行,并返回nullptr表示没有输出数据。

这个和cuda里的stream有点像。

流水线处理工作量最好足够大!!!!!!否则容易无法隐藏调度!!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值