增加线程数减少时间

时间:2014-03-22 19:06:40

标签: multithreading openmp

我是openmp的新手。从openmp官方页面的教程开始 https://www.youtube.com/playlist?list=PLLX-Q6B8xqZ8n8bwjGdzBJ25X2utwnoEG

在该页面中有一个hello world程序,通过近似积分来计算pi。 我只是按照说明编写下面的代码,但随着我增加更改NUM_THREADS的线程数,它的时间速度也会增加。在视频中,速度会下降。

我正在一个64 cpu的远程服务器上执行该程序,每个cpus有8个核心。

#include <stdio.h>
#include <omp.h>
static long num_steps = 100000;
double step;

#define NUM_THREADS 2 

int main()
{
    int i, nthreads; double pi, sum[NUM_THREADS];
    double start_t;

    step = 1.0 / (double) num_steps;

    omp_set_num_threads(NUM_THREADS);

    start_t = omp_get_wtime();
    #pragma omp parallel
    {
        int i, id, nthrds;
        double x;

        id = omp_get_thread_num();
        nthrds = omp_get_num_threads();
        if (id == 0) nthreads = nthrds;
        for (i = id, sum[id] = 0.0; i < num_steps; i = i + nthrds) {
            x = (i + 0.5) * step;
            sum[id] += 4.0 / (1.0 + x*x);
        }
    }
    for (i = 0, pi = 0.0; i < nthreads; i++) {
        pi += sum[i] * step;
    }
    printf("%f\n", omp_get_wtime() - start_t);
}

1 个答案:

答案 0 :(得分:2)

这是使用共享阵列实现缩减的不好方法。 sum的连续元素彼此太靠近,因此位于同一缓存行中。在x86 / x64等缓存一致的体系结构上,这会导致称为 false sharing 的问题。以下简单的修改将摆脱它:

double sum[8*NUM_THREADS];

#pragma omp parallel
{
    ...
    for (i = id, sum[id] = 0.0; i < num_steps; i = i + nthrds) {
        ...
        sum[8*id] += 4.0 / (1.0 + x*x);
    }
}
for (i = 0, pi = 0.0; i < nthreads; i++) {
    pi += sum[8*i] * step;
}

仅显示相关更改。这个想法很简单:不是让线程访问sum的连续元素,而是让它们访问每个第8个元素。因此,可以保证线程不会像大多数现代CPU共享同一个高速缓存行,高速缓存行长度为64个字节,并且对应于64 / sizeof(double) = 8个数组元素。

编辑:我的错误,应该首先看视频。在显示运行代码的结果之后解释错误共享。如果你没有在你的情况下获得任何加速,那可能是因为较新的CPU代更好地处理错误共享。