参考学习文档:https://www.doc88.com/p-9708754893392.html
这里以计算PI值为例子,首先计算公式为:
常规计算
代码实现:
#include
#include
static long num_steps = 100000000;
double step;
int main() {
int i; double x, pi, sum = 0.0, start_time, end_time;
step = 1.0 / (double)num_steps;
start_time = clock();
for (i = 1; i <= num_steps; i++){
x = (i - 0.5) * step; //这里是减号,可能公式打错了,问题并未排查,不过不影响openMP分析
sum = sum + 4.0 / (1.0 + x * x);
}
pi = step * sum;
end_time = clock();
printf(" pi = %f \n Running time %f \n ", pi, double(end_time - start_time)/ CLOCKS_PER_SEC);
}
最终运行结果:(经过多次运行结果,结果均是这个值)
次数 | 第一次 | 第二次 | 第三次 |
---|---|---|---|
时间 | 1.1750s | 1.1790s | 1.1820s |
pi | 3.141593 | 3.141593 | 3.141593 |
并行计算
#include
#include
#include
static long num_steps = 100000000;
double step;
#define NUM_THREADS 4
int main() {
int i; double x, pi, sum[NUM_THREADS], start_time, end_time;
step = 1.0 / (double)num_steps;
omp_set_num_threads(NUM_THREADS);//这里指定开启线程数量
start_time = omp_get_wtime();
#pragma omp parallel
{
int m_id; double x; //这里相当于定义为私有变量
m_id = omp_get_thread_num();
sum[m_id] = 0.0;
for (int i = m_id; i < num_steps; i = i + NUM_THREADS) {//这里不加int的话无法正确执行出
x = (i + 0.5) * step; //
sum[m_id] += 4.0 / (1.0 + x * x);
}
printf(" 线程 id: %d ,num[%d] : %f \n", m_id, m_id, sum[m_id]);
}
for (i = 0, pi = 0.0; i < NUM_THREADS; i++)
pi += sum[i] * step;
end_time = omp_get_wtime();
printf(" pi =%f \n Running time %f \n ", pi, (end_time - start_time) );
}
这里如果for循环中int不加入的话,经过多次运行,结果不正确
次数 | 第一次 | 第二次 | 第三次 |
---|---|---|---|
pi | 3.233750 | 3.369250 | 3.091066 |
时间 | 2.0229s | 1.7208s | 1.991856s |
排查之后发现需要加上int值
当我for循环中加上int之后,程序开始可以正确运行,总体上减少三分之二以上的运算时间
次数 | 第一次 | 第二次 | 第三次 | 第四次 | 第五次 | 第六次 |
---|---|---|---|---|---|---|
pi | 3.141593 | 3.141593 | 3.141593 | 3.141593 | 3.141593 | 3.141593 |
时间 | 0.562953s | 0.569765s | 0.455320s | 0.407920s | 0.415278s | 0.451851s |
使用reduction语句
合并每个线程的sum值,可以减少一个for循环的代码和运算时间
#include
#include
#include
static long num_steps = 100000000;
double step;
#define NUM_THREADS 4
void main()
{
int i, id; double x, pi, sum, start_time, end_time;
step = 1.0 / (double)num_steps;
omp_set_num_threads(NUM_THREADS);
start_time = omp_get_wtime();
sum = 0;
#pragma omp parallel private(i,x,id) reduction(+:sum)//这里私有变量缺少i的话,结果出错,缺少x精度出错,缺少id显示线程id出错
{
id = omp_get_thread_num();
//#pragma omp for
for (i = id; i < num_steps; i = i + NUM_THREADS) {
x = (i + 0.5) * step;
sum += 4.0 / (1.0 + x * x);
}
printf(" 线程 id: %d ,sum : %f \n", id, sum);
}
pi = sum * step;
end_time = omp_get_wtime();
printf(" pi =%f \n Running time %f \n ", pi, (end_time - start_time) );
}
这里源ppt书写方式无法运行,这里有变量冲突 private、shared、reduction里面的变量,只能出现一次。
可以理解为一个变量不能同时声明privete、shared
经过多次运行结果比较,运行时间误差不超过0.05:
次数 | 第一次 | 第二次 | 第三次 | 第四次 | 第五次 | 第六次 |
---|---|---|---|---|---|---|
pi | 3.141593 | 3.141593 | 3.141593 | 3.141593 | 3.141593 | 3.141593 |
时间 | 0.297697s | 0.295788s | 0.296332s | 0.296123s | 0.297550s | 0.296842s |
保存共享变量: CRITICAL制导
#include
#include
#include
static long num_steps = 100000000;
double step;
#define NUM_THREADS 4
void main()
{
int i; double x, sum, pi = 0.0, start_time, end_time;
step = 1.0 / (double)num_steps;
omp_set_num_threads(NUM_THREADS);
start_time = omp_get_wtime();
#pragma omp parallel private (i,x, sum)
{
int id = omp_get_thread_num();
for (i = id, sum = 0.0; i < num_steps; i = i + NUM_THREADS) {
x = (i + 0.5) * step;
sum += 4.0 / (1.0 + x * x);
}
#pragma omp critical
pi += sum* step;
}
end_time = omp_get_wtime();
printf(" pi =%f \n Running time %f \n ", pi, (end_time - start_time));
}
次数 | 第一次 | 第二次 | 第三次 | 第四次 | 第五次 | 第六次 |
---|---|---|---|---|---|---|
pi | 3.141593 | 3.141593 | 3.141593 | 3.141593 | 3.141593 | 3.141593 |
时间 | 0.295597s | 0.295902s | 0.296769s | 0.295258s | 0.295042s | 0.295075s |