cpu并行计算——c++实现

前言

一转眼 2023 年已经过了 3 个月了,博客不知不觉又搁置了不少时间,唉,还是需要持之以恒啊。

并行

为啥想起来搞这个,是因为有业务需要在没有显卡的主机上做加速,在对原代码做逻辑梳理之后,包括通过空间换时间的方式,实在是没有其他可以有显著提升的地方了,就考虑 cpu 并行计算。

因为工程是用的 c++写的,所以也就看了下 c++相关的,一看原来就打开个OpenMp就开启了多处理器,直接来看咋搞吧。

工程配置

新建 c++控制台工程,这个就不需要演示了,我们打开工程属性设置,选择C/C++ =》 语言 =》 OpenMp 支持,选择(没有汉化的就找对应单词吧,像什么 Language 啊 OpenMp 啊选 Yes 之类的)。

工程配置

常用命令

指令说明示例
parallel紧跟的代码片段会被并行执行#pragma omp parallel
parallel for直接跟 for 循环即可,不需要代码片段#pragma omp parallel for
函数说明
omp_get_num_procs获取可并行的处理器个数
omp_set_num_threads设置并行处理器个数,对应有个 get 函数
omp_get_thread_num在并行代码中获取当前执行的处理器编号
omp_get_wtime计时用的

测试

接下来我们先来引入头文件,然后测试下看看自己电脑是几个逻辑处理器(不是看内核啊这里)。

1
2
3
4
5
6
7
#include <iostream>
#include "omp.h"

int main()
{
std::cout << omp_get_num_procs() << std::endl;
}

omp.h:这个就是 OpenMp 的头文件。
omp_get_num_procs:获取处理器个数。

如果不出意外的,就能正常输出结果,当然可能也有意外啊,这个自行解决吧,毕竟这玩意儿都是自带的,没啥特殊操作(可能是我这比较顺,有问题的可以交流)。

之后我们也来简单执行个函数测试下,在刚才那句紧跟着写上。

1
2
3
4
#pragma omp parallel
{
std::cout << "Hello World! " << omp_get_thread_num() << std::endl;
}

#pragma omp parallel:没错,这个就是代表这里用多处理执行,一般可以直接跟上单行函数或者 for 循环
omp_get_thread_num:处理器索引,可以理解成线程 id

这个就是开启默认个(一般是满)处理器来执行,可以通过设置处理器个数来修改。

1
2
3
4
5
omp_set_num_threads(4); // 注意相关设置项一定在开启之前
#pragma omp parallel
{
std::cout << "Hello World! " << omp_get_thread_num() << std::endl;
}

图像处理

前面那些测试只是为了知道这玩意儿咋用,接下来拿个示例来看下实际的效果。

这里我们假设一个需求,处理一张图(三通道)中某个通道值大于 100 的,并且做对应处理。

这里考虑并行处理,就按照列数/处理器个数来模拟处理图像。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void testImage(cv::Mat& img, int index)
{
std::cout << "index = " << index << std::endl;
// 这里因为是12个处理器,直接用了
int col_begin = IMAGE_COLS / 12 * index;
int col_end = IMAGE_COLS / 12 * (index + 1) - 1;

for (int i = 0; i < IMAGE_ROWS; i++)
{
for (int j = col_begin; j < col_end; j++)
{
if (img.at<cv::Vec3b>(i, j)[0] > 100)
{
img.at<cv::Vec3b>(i, j)[0] -= 100;
img.at<cv::Vec3b>(i, j)[1] += 100;
}
}
}
}

然后我们来调用这个函数来对应测试下时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    cv::Mat img = cv::imread("0.jpg");
if (!img.empty())
{
cv::Mat img_single = img.clone();
double t1 = omp_get_wtime();
int total = omp_get_num_procs();
for (int i = 0; i < total; i++)
{
testImage(img_single, i);
}
double t2 = omp_get_wtime();
std::cout << "1 use time : " << t2 - t1 << " s" << std::endl;
cv::imwrite("0_single.jpg", img_single);

for (int i = 2; i <= 12; i += 2)
{
cv::Mat image = img.clone();
omp_set_num_threads(i);
t1 = omp_get_wtime();
#pragma omp parallel
{
testImage(image, omp_get_thread_num(), i);
}
t2 = omp_get_wtime();
std::cout << i << " use time : " << t2 - t1 << " s" << std::endl;
cv::imwrite("0_" + std::to_string(i) + ".jpg", image);
}
}

看下执行效果吧。

测试结果

通过这个结果,可能跟我写的示例有关,2 个处理器操作速度是最快,我起初以为是开的越多越快,也可能是还没摸透,后续鼓捣的时候有变动的话,就继续更新吧。

小结

并行之路,道阻且长啊,还有 gpu 的并行计算,这都是提速的方式,也都是吃硬件的时候了。


cpu并行计算——c++实现
http://www.aprilblank.top/c++/cpu_parallel.html
作者
AprilBlank
发布于
2023年3月12日
许可协议