OpenMP并行域学习

参考学习文档: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


image.png

经过多次运行结果比较,运行时间误差不超过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

你可能感兴趣的:(OpenMP并行域学习)