代码中有两个开销来源,即critical region
,并调用rand()
。代替rand()
use rand_r:
我认为您正在寻找 rand_r(),它明确采用
当前 RNG 状态作为参数。那么每个线程应该有它的
自己的种子数据副本(是否希望每个线程以
相同的种子或不同的种子取决于你在做什么,在这里你
希望它们不同,否则您会一次又一次地得到同一行)。
可以使用 OpenMP 子句删除关键区域reduction
。此外,您也不需要调用sqrt
也不手动将点除以线程(i.e., long points = total_points / threads;
), 您可以使用#pragma omp for
为了那个原因。所以你的代码将如下所示:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <omp.h>
#include <sys/sysinfo.h>
int main(void)
{
long total_points;
long total_m = 0;
int threads = get_nprocs();
printf("Enter the number of points: ");
scanf("%ld", &total_points);
omp_set_num_threads(threads);
#pragma omp parallel
{
unsigned int myseed = omp_get_thread_num();
#pragma omp for reduction (+: total_m)
for(long i = 0; i < total_points; i++){
if(pow((double) rand_r(&myseed) / (RAND_MAX), 2) + pow((double) rand_r(&myseed) / (RAND_MAX), 2) <= 1)
total_m++;
}
}
printf("Pi is roughly %lf\n", (double) 4*total_m / (double) total_points);
}
在我的机器上快速测试输入 1000000000:
sequential : 16.282835 seconds
2 threads : 8.206498 seconds (1.98x faster)
4 threads : 4.107366 seconds (3.96x faster)
8 threads : 2.728513 seconds (5.96x faster)
请记住,我的机器只有 4 个核心。尽管如此,为了进行更有意义的比较,应该尝试尽可能地优化顺序代码,然后将其与并行版本进行比较。当然,如果顺序版本尽可能优化,并行版本的加速可能会下降。例如,根据提供的代码的顺序版本测试当前的并行版本而不进行修改@用户3666197,产生以下结果:
sequential : 9.343118 seconds
2 threads : 8.206498 seconds (1.13x faster)
4 threads : 4.107366 seconds (2.27x faster)
8 threads : 2.728513 seconds (3.42x faster)
然而,我们还可以改进并行版本以及等等,第四。例如,如果一个人采取@用户3666197版本,修复更新的竞争条件coordinates
(在线程之间共享),并添加 OpenMP #pragma omp for,我们有以下代码:
int main(void)
{
double start = omp_get_wtime();
long points = 1000000000; //....................................... INPUT AVOIDED
long m = 0;
unsigned long HAUSNUMERO = 1;
double DIV1byMAXbyMAX = 1. / RAND_MAX / RAND_MAX;
int threads = get_nprocs();
omp_set_num_threads(threads);
#pragma omp parallel reduction (+: m )
{
unsigned int aThreadSpecificSEED_x = HAUSNUMERO + 1 + omp_get_thread_num();
unsigned int aThreadSpecificSEED_y = HAUSNUMERO - 1 + omp_get_thread_num();
#pragma omp for nowait
for(long i = 0; i < points; i++)
{
double x = rand_r( &aThreadSpecificSEED_x );
double y = rand_r( &aThreadSpecificSEED_y );
m += (1 >= ( x * x + y * y ) * DIV1byMAXbyMAX);
}
}
double end = omp_get_wtime();
printf("%f\n",end-start);
printf("Pi is roughly %lf\n", (double) 4*m / (double) points);
}
产生以下结果:
sequential : 9.160571 seconds
2 threads : 4.769141 seconds (1.92 x faster)
4 threads : 2.456783 seconds (3.72 x faster)
8 threads : 2.203758 seconds (4.15 x faster)
我正在使用标志进行编译-O3 -std=c99 -fopenmp
,并使用 gcc 版本4.9.3 (MacPorts gcc49 4.9.3_0)
.