所以用我相当简单的OpenMP并行化for循环,我真的搞不懂这一点。当在相同的输入大小上运行时,P=1运行大约50秒,但是运行P=2需要大约300秒,而P=4运行大约250秒。
下面是并行化的循环
double time = omp_get_wtime();
printf("Input Size: %d\n", n);
#pragma omp parallel for private(i) reduction(+:in)
for(i = 0; i < n; i++) {
double x = (double)(rand() % 10000)/10000;
double y = (double)(rand() % 10000)/10000;
if(inCircle(x, y)) {
in++;
}
}
double ratio = (double)in/(double)n;
double est_pi = ratio * 4.0;
time = omp_get_wtime() - time;运行时:
p=1,n=1073741824 - 52.764秒
p=2,n=1073741824 - 301.66秒
p=4,n=1073741824 - 274.784秒
p=8,n=1073741824 - 188.224秒
在Ubuntu20.04VM上运行,该虚拟机具有8核至强5650和16 of DDR3 EEC,安装在具有70 of内存的双至强5650系统上的FreeNas之上。
部分解决方案:
当在多个线程上运行时,循环内的rand()函数会导致时间跳转。
发布于 2020-11-16 08:46:40
由于rand()使用从上一次调用中保存的状态来生成下一个PRN,因此它不能同时在多个线程中运行。多个线程需要同时读/写PRNG状态。
POSIX states that rand() need not be thread safe.这意味着你的代码不能正常工作。或者,C库可能会放入一个互斥锁,这样一次只能有一个线程调用rand()。这就是正在发生的事情,但它大大减慢了代码的速度。试图访问rand临界区的线程几乎全部消耗掉了,因为它们所做的任何其他事情都不会占用任何重要的时间。
要解决这个问题,可以尝试使用rand_r(),它不使用共享状态,而是传递应该用于状态的seed值。
请记住,对每个线程使用相同的种子将违背在蒙特卡洛模拟中增加试验数量的目的。每个线程只使用完全相同的伪随机序列。尝试如下所示:
unsigned int seed;
#pragma omp parallel private(seed)
{
seed = omp_get_thread_num();
#pragma omp for private(i) reduction(+:in)
for(i = 0; i < n; i++) {
double x = (double)(rand_r(&seed) % 10000)/10000;
double y = (double)(rand_r(&seed) % 10000)/10000;
if(inCircle(x, y)) {
in++;
}
}
}顺便说一句,你可能会注意到你的估计有偏差。X和y需要在0,1的范围内均匀分布,但它们不是。
https://stackoverflow.com/questions/64850966
复制相似问题