代码之家  ›  专栏  ›  技术社区  ›  Freelancer

OpenMP并行两种方法的区别

  •  0
  • Freelancer  · 技术社区  · 3 年前

    我只是想通过OpenMP的汇总来评估函数的集成,通过使用数组来保存每个步骤中计算的每个值>取所有值的总和;并取不带数组的和。

    代码为:

    double f(double x)
    {
        return sin(x)*sin(x)/(x*x+1);
    }
    

    方法1

        long i = 0;
        const long NUM_STEP = 100000;
        double sum[NUM_STEP];
        double from = 0.0, to = 1.0;
        double step = (to - from)/NUM_STEP;
        double result = 0;
    
        #pragma omp parallel for shared(sum) num_threads(4)
        for(i=0; i<NUM_STEP; i++)
            sum[i] = step*f(from+i*step);
        for(i=0; i<NUM_STEP; i++)
            result += sum[i];
        printf("%lf", result);
    

    方法2

        long i = 0;
        const long NUM_STEP = 100000;
        double from = 0.0, to = 1.0;
        double step = (to - from)/NUM_STEP;
        double result = 0;
    
        #pragma omp parallel for shared(result) num_threads(4)
        for(i=0; i<NUM_STEP; i++)
            result += step*f(from+i*step);
        printf("%lf", result);
    

    但结果太不一样了。方法1给出了稳定的值,但方法2给出了可变的值。以下是一个示例:

    方法1:0.178446

    方法2:0.158738

    方法1的值为真(由另一个工具检查)。

    0 回复  |  直到 3 年前
        1
  •  3
  •   dreamcrash    3 年前

    TL;博士 第一种方法没有 比赛条件 而第二种方法具有。

    第一种方法没有竞争条件,而第二种方法有。即,在第一种方法中:

    #pragma omp parallel for shared(sum) num_threads(4)
    for(i=0; i<NUM_STEP; i++)
        sum[i] = step*f(from+i*step);
    for(i=0; i<NUM_STEP; i++)
        result += sum[i];
    

    每个线程都保存操作的结果 step*f(from+i*step); 在阵列的不同位置 sum[i] 在那之后 主人 线程,按顺序减少数组上保存的值 sum 即:

    for(i=0; i<NUM_STEP; i++)
        result += sum[i];
    

    实际上,您可以在这个版本上做一些改进;而不是分配数组 总和 大小与数量相同 NUM_STEP ,您可以将其分配为与线程数相同的大小,每个线程将保存在与其线程数相等的位置 ID 即:

    int total_threads = 4;
    double sum[total_threads];
    #pragma omp parallel num_threads(total_threads)
    {
      int thread_id = omp_get_thread_num();
      for(i=0; i<NUM_STEP; i++)
          sum[thread_id] += step*f(from+i*step);
      for(i=0; i< total_threads; i++)
          result += sum[i];
    }
    

    尽管如此,最好的方法将是实际修复第二种方法。

    第二种方法是 比赛条件 关于变量的更新 result :

    #pragma omp parallel for shared(result) num_threads(4)
    for(i=0; i<NUM_STEP; i++)
        result += step*f(from+i*step);
    

    因为 结果 变量由多个线程以非线程安全的方式并发更新。

    为了解决这个问题 比赛条件 你需要使用 reduction 条款:

    #pragma omp parallel for reduction(+:result) num_threads(4)
    for(i=0; i<NUM_STEP; i++)
        result += step*f(from+i*step);