并发编程(c++)——2.1线程池在cpu密集任务中的应用
·
本文续接并发编程(c++)——2.线程池模式,主要介绍线程池在cpu密集任务中的应用,通过分治思想将任务分解成多个小任务,将每个小任务放在线程池中不同线程中,主要强调了线程数量在cpu密集计算中的作用,并通过矩阵计算作为案例。
背景
生产任务中存在大量的密集计算需求,如科学计算、大数据计算、人工智能等场景。
问题
如何将并发编程应用到cpu密集任务中,提高计算速度。
方案
分治思想+线程池。
cpu密集任务需要将完整任务分解成可以并行的小任务,将每个小任务放在线程池中不同线程中,最后综合结果.
在这个过程中一直在使用cpu计算能力,如果一个核心上同时存在运行多个小任务,此时就会出现线程切换,这会带来多余的上下文切换,降低处理速度。
所以在分配线程池的时候需要将线程数和逻辑核心数保持一致,这样就可以避免线程切换,提高处理速度。
案例
计算矩阵的和,大型矩阵的元素和计算是一个典型的cpu密集任务,将矩阵分解成多个小矩阵,每个小矩阵计算和,最后将所有小矩阵的和相加得到最终结果。
实现
1.创建一个矩阵
// 创建一个矩阵
std::vector<std::vector<float>> create_matrix(int n, int m) {
std::vector<std::vector<float>> matrix(n, std::vector<float>(m));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
matrix[i][j] = 1;
}
}
return matrix;
}
2.计算一个块的和
// 求和矩阵的块
double block_sum(std::vector<std::vector<float>> &matrix,int bolck_size, int i, int j)
{
//提取矩阵的块
float sum=0;
for(int k=0;k<bolck_size;k++)
{
for(int l=0;l<bolck_size;l++)
{
sum=sum+matrix[i*bolck_size+k][j*bolck_size+l];
}
}
return sum;
}
3.对比并发计算和串行计算的速度
线程池的功能来自于,并发编程(c++)——2.线程池模式
void test_cpu() {
// 初始化线程池
size_t cpu_cores = std::thread::hardware_concurrency();
int thread_counts = cpu_cores * 2;
std::cout << "cpu cores: " << cpu_cores << std::endl;
ThreadPool pool(thread_counts);
// 定义矩阵的行数和列数,均为1024
int n=100000, m=10000;
// 调用create_matrix函数创建一个n行m列的二维浮点数矩阵
std::vector<std::vector<float>> matrix = create_matrix(n, m);
// 1.直接求和
auto t1= std::chrono::high_resolution_clock::now();
double sum=0;
for (auto &row : matrix) {
for (auto &val : row) {
sum += val;
}
}
auto t2= std::chrono::high_resolution_clock::now();
std::chrono::duration<double> time_span = std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1);
std::cout << "矩阵直接求和的结果: " << sum << std::endl;
std::cout << "Time: " << time_span.count() << "s" << std::endl;
// 2.分治求和
auto t3= std::chrono::high_resolution_clock::now();
std::vector<std::future<double>> futures;
int bolck_size=100;
for(int i=0;i<n/bolck_size;i++)
{
for(int j=0;j<m/bolck_size;j++)
{
// std::cout<<"i: "<<i<<" j: "<<j<<std::endl;
// 分块线程池运算
futures.push_back(pool.enqueue([&matrix, bolck_size, i, j]() {
return block_sum(matrix, bolck_size, i, j);
}));
}
}
// 等待所有任务完成
std::vector<double> results;
for(auto& future:futures)
{
results.push_back(future.get());
// std::cout<<"result: "<<future.get()<<std::endl;
}
// 求和
sum=0;
for(auto val:results)
{
sum+=val;
}
auto t4= std::chrono::high_resolution_clock::now();
time_span = std::chrono::duration_cast<std::chrono::duration<double>>(t4 - t3);
std::cout << "矩阵分治求和的结果: " << sum << std::endl;
std::cout << "Time: " << time_span.count() << "s" << std::endl;
}
运算结果
cpu cores: 20
矩阵直接求和的结果: 1e+09
Time: 1.87203s
矩阵分治求和的结果: 1e+09
Time: 0.797735s
并发计算的速度是串行计算的2倍左右。
总结
并发编程能够提高cpu密集任务的处理速度,核心思想是分治思想+线程池,但是需要合理分配线程池,避免线程切换带来的性能损失。
更多推荐

所有评论(0)