首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >OpenMP:并行工作负载没有加速

OpenMP:并行工作负载没有加速
EN

Stack Overflow用户
提问于 2020-11-16 07:42:49
回答 1查看 68关注 0票数 1

所以用我相当简单的OpenMP并行化for循环,我真的搞不懂这一点。当在相同的输入大小上运行时,P=1运行大约50秒,但是运行P=2需要大约300秒,而P=4运行大约250秒。

下面是并行化的循环

代码语言:javascript
复制
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()函数会导致时间跳转。

EN

回答 1

Stack Overflow用户

发布于 2020-11-16 08:46:40

由于rand()使用从上一次调用中保存的状态来生成下一个PRN,因此它不能同时在多个线程中运行。多个线程需要同时读/写PRNG状态。

POSIX states that rand() need not be thread safe.这意味着你的代码不能正常工作。或者,C库可能会放入一个互斥锁,这样一次只能有一个线程调用rand()。这就是正在发生的事情,但它大大减慢了代码的速度。试图访问rand临界区的线程几乎全部消耗掉了,因为它们所做的任何其他事情都不会占用任何重要的时间。

要解决这个问题,可以尝试使用rand_r(),它不使用共享状态,而是传递应该用于状态的seed值。

请记住,对每个线程使用相同的种子将违背在蒙特卡洛模拟中增加试验数量的目的。每个线程只使用完全相同的伪随机序列。尝试如下所示:

代码语言:javascript
复制
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的范围内均匀分布,但它们不是。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64850966

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档