OPENMP серийная версия кода быстрее, чем параллельная версия, как я могу это исправить - PullRequest
0 голосов
/ 25 апреля 2020

вот программа, которая выполняет некоторые вычисления, и я пытаюсь использовать потоки, чтобы она работала быстрее, но я не могу заставить ее работать быстрее, чем последовательная версия.

последовательный вывод

Function: y(x) = sin(x) [note that x is in radians]
Limits of integration: x1 = 7.000000, x2 = 2.000000 
Riemann sum with 5000 steps, a.k.a. dx=-0.001000 
Computed integral: 1.170175 
Exact integral:    1.170049 
Percent error:     0.010774 % 
Work took 0.182533 milliseconds

параллельный вывод равен

Function: y(x) = sin(x) [note that x is in radians]
Limits of integration: x1 = 7.000000, x2 = 2.000000 
Riemann sum with 5000 steps, a.k.a. dx=-0.001000 
Computed integral: 1.170175 
Exact integral:    1.170049 
Percent error:     0.010774 % 
Work took 0.667334 milliseconds

Вот код

#include <stddef.h>  // for size_t
#include <stdio.h>
#include <stdlib.h>     /* atoi, atof */
#include <math.h>
#include "omp.h" // just used for timing

int main(int argc, char *argv[]) {
   double start, end;
   start = omp_get_wtime(); // Start our work timer

   // BEGIN TIMED CODE BLOCK
   double x, y;
   double x1, x2; // Limits of integration
   double dx;
   double ysum, integral;
   size_t i;
   size_t nsteps;

   // Read in command line arguments
   x1 = atof(argv[1]); // lower x limit
   x2 = atof(argv[2]); // upper x limit
   nsteps = atof(argv[3]); // number of steps in Riemann sum
  omp_set_num_threads(2); 
   // Compute delta x
      dx = (x2 - x1)/nsteps; // delta x for the Riemann sum

        // Perform numeric integration via Riemann sum
    ysum = 0;
        // Temporary variable to hold the sum prior to multiplication by dx
    #pragma omp parallel shared(ysum) private(x,y)
    {
        #pragma omp for 
        for (i=0; i<nsteps; i++) {
                x = x1 + i*dx; // x value at this step
                y = sin(x); // y(x) at this step; note that x is always in radians
            #pragma omp critical
            ysum += y; // summation of y(x)
        }               
    #pragma omp critical
    integral = ysum * dx; // Our computed integral: the summation of y(x)*dx
       // END TIMED CODE BLOCK
    }


   end = omp_get_wtime(); // Stop our work timer

   double analytic = -cos(x2) + cos(x1); // The known, exact answer to this integration problem

   printf("Function: y(x) = sin(x) [note that x is in radians]\n");
   printf("Limits of integration: x1 = %lf, x2 = %lf \n", x1, x2);
   printf("Riemann sum with %ld steps, a.k.a. dx=%lf \n", nsteps, dx); 
   printf("Computed integral: %lf \n", integral);
   printf("Exact integral:    %lf \n", analytic);
   printf("Percent error:     %lf %% \n", fabs((integral - analytic) / analytic)*100);
   printf("Work took %f milliseconds\n", 1000 * (end - start));
   return 0;
}

выход изменяется, когда я удаляю критические разделы, поэтому я предполагаю, что я все сделал правильно

1 Ответ

2 голосов
/ 25 апреля 2020

Каждый раз, когда у вас есть #pragma omp critical, вы устанавливаете барьер для эффективной многопоточности. Вы можете использовать директиву #pragma omp parallel for вместе с предложением reduction для распараллеливания вашего l oop.

#pragma omp parallel for reduction(+:ysum)
for (int i = 0; i < nsteps; ++i) {
    auto x = x1 + i * dx;
    auto y = sin(x);
    ysum += y;
}

integral = ysum * dx;

В нем объявлены временные переменные, которые используются в l oop, так что каждый поток будет иметь свою собственную копию (тело l oop может быть переписано без необходимости x или y). Предложение reduce (в данном случае) будет хранить отдельное значение ysum для каждого потока, а затем в конце добавит все эти значения вместе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...