Ich habe den folgenden Code, der OMP verwendet, um eine Monte-Carlo-Methode zu parallelisieren. Meine Frage ist, warum die serielle Version des Codes (monte_carlo_serial) viel schneller läuft als die parallele Version (monte_carlo_parallel). Ich führe den Code auf einem Rechner mit 32 Kernen aus und bekomme folgendes Ergebnis auf die Konsole:Warum lässt OpenMP den Code langsamer laufen?
-bash-4.1 $ gcc -fopenmp hello.c;
-bash-4.1 $ ./a.out
Pi (Serial): 3,140856
Zeit genommen 0 Sekunden 50 Millisekunden
Pi (Parallel): 3,3
Zeit genommen 127 Sekunden 990 Millisekunden
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>
#include <time.h>
int niter = 1000000; //number of iterations per FOR loop
int monte_carlo_parallel() {
double x,y; //x,y value for the random coordinate
int i; //loop counter
int count=0; //Count holds all the number of how many good coordinates
double z; //Used to check if x^2+y^2<=1
double pi; //holds approx value of pi
int numthreads = 32;
#pragma omp parallel firstprivate(x, y, z, i) reduction(+:count) num_threads(numthreads)
{
srand48((int)time(NULL)^omp_get_thread_num()); //Give random() a seed value
for (i=0; i<niter; ++i) //main loop
{
x = (double)drand48(); //gets a random x coordinate
y = (double)drand48(); //gets a random y coordinate
z = ((x*x)+(y*y)); //Checks to see if number is inside unit circle
if (z<=1)
{
++count; //if it is, consider it a valid random point
}
}
}
pi = ((double)count/(double)(niter*numthreads))*4.0;
printf("Pi (Parallel): %f\n", pi);
return 0;
}
int monte_carlo_serial(){
double x,y; //x,y value for the random coordinate
int i; //loop counter
int count=0; //Count holds all the number of how many good coordinates
double z; //Used to check if x^2+y^2<=1
double pi; //holds approx value of pi
srand48((int)time(NULL)^omp_get_thread_num()); //Give random() a seed value
for (i=0; i<niter; ++i) //main loop
{
x = (double)drand48(); //gets a random x coordinate
y = (double)drand48(); //gets a random y coordinate
z = ((x*x)+(y*y)); //Checks to see if number is inside unit circle
if (z<=1)
{
++count; //if it is, consider it a valid random point
}
}
pi = ((double)count/(double)(niter))*4.0;
printf("Pi (Serial): %f\n", pi);
return 0;
}
void main(){
clock_t start = clock(), diff;
monte_carlo_serial();
diff = clock() - start;
int msec = diff * 1000/CLOCKS_PER_SEC;
printf("Time taken %d seconds %d milliseconds \n", msec/1000, msec%1000);
start = clock(), diff;
monte_carlo_parallel();
diff = clock() - start;
msec = diff * 1000/CLOCKS_PER_SEC;
printf("Time taken %d seconds %d milliseconds \n", msec/1000, msec%1000);
}
Wie die verwandten Referenzen Ihnen sagen, wird erwartet, dass die von allen Threads eingenommene Gesamtzeit für die Anzahl der Threads zunimmt. Es scheint keinen Sinn zu geben, x, y als zuerst privat zu definieren, statt einfach mit lokalem Geltungsbereich zu definieren, insbesondere da die meiste Zeit in serialisierten Drähten verbracht wird. – tim18
Sie sollten folgendes beachten: 1/'drand48()' ist nicht threadsicher, da es einen globalen Zustand verwendet (schauen Sie sich 'drand48_r()' an, um einen Ersatz zu erhalten, wenn Sie diesen RNG beibehalten wollen); und 2/'clock()' gibt Ihnen CPU-Zeit, nicht verstrichene Zeit ... Sie sollten 'omp_get_wtime()' für alle Ihre Timing-Aufgaben hier verwenden. Schließlich hat Ihr Problem nichts mit falschem Teilen von "count" zu tun. – Gilles