我想在OpenMP中使用线程实现下面代码的并行版本,有没有更好的方法呢?
/* Program to compute Pi using Monte Carlo methods */
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <time.h>
#define SEED 35791246
int main(int argc, char* argv)
{
int niter=0;
double x,y;
int i,count=0; /* # of points in the 1st quadrant of unit circle */
double z;
double pi;
clock_t end_time, start_time;
printf("Enter the number of iterations used to estimate pi: ");
scanf("%d",&niter);
start_time = clock();
/* initialize random numbers */
srand(SEED);
count=0;
#pragma omp parallel for
for ( i=0; i<niter; i++) {
x = (double)rand()/RAND_MAX;
y = (double)rand()/RAND_MAX;
z = x*x+y*y;
if (z<=1) count++;
}
#pragma omp task
pi=(double)count/niter*4;
#pragma omp barrier
end_time = clock();
printf("# of trials= %d , estimate of pi is %g, time= %f \n",niter,pi, difftime(end_time, start_time));
return 0;
}
答案 0 :(得分:2)
rand
功能在这里使用不是一个好主意。要么它不是线程安全的,你将有线程获得重复值(不是非常随机),或者它将有一个锁,MP版本将比单线程版本慢。
我建议找另一个可以从多个线程同时使用的随机数生成器。
答案 1 :(得分:2)
可以通过更正一些OpenMP错误来改进。首先,由于您在所有并行线程中总结({副本] count
,因此您需要在并行段末尾应用减少运算符,以将所有这些运算符组合回单个值。此外,变量i
,x
,y
和z
需要为每个并行线程设置单独的实例 - 您不希望线程使用相同的线程!要指定所有这些,循环顶部的#pragma
指令应为:
#pragma omp parallel for private(i, x, y, z) reduction(+:count)
此外,其范围是for
循环,因此您无需执行任何其他操作;循环退出后,线程会自动同步。 (并且您需要同步以使count
包含来自所有线程的所有增量!)特别是,您的task
和barrier
pragma是没有意义的,因为此时您又回到了只有一个线程 - 而且,将单个计算放在并行任务中是没有意义的。
在这些情况下,gabe提出了系统随机数生成器可能缓慢和/或随机性差的问题。您可能希望调查系统中的详细信息,并在每个线程中为其提供一个新的随机种子,或根据您找到的内容使用不同的随机数生成器。
除此之外,它看起来相当合理。你可以对该算法做很多其他事情,因为它简短且可以平行化。