2

我正在尝试使用 OpenMP 测试 Pi 计算问题。我有这个代码:

#pragma omp parallel private(i, x, y, myid) shared(n) reduction(+:numIn) num_threads(NUM_THREADS)
{
printf("Thread ID is: %d\n", omp_get_thread_num());
myid = omp_get_thread_num();
printf("Thread myid is: %d\n", myid);

  for(i = myid*(n/NUM_THREADS); i < (myid+1)*(n/NUM_THREADS); i++) {
//for(i = 0; i < n; i++) {

    x = (double)rand()/RAND_MAX;

    y = (double)rand()/RAND_MAX;

    if (x*x + y*y <= 1) numIn++;

  }
printf("Thread ID is: %d\n", omp_get_thread_num());

}

  return 4. * numIn / n;

}

当我编译gcc -fopenmp pi.c -o hello_pi并运行它时time ./hello_pin = 1000000000我得到

真正的 8m51.595s

用户 4m14.004s

系统 60m59.533s

当我用一个线程运行它时,我得到

实际0m20.943s

用户 0m20.881s

系统 0m0.000s

我错过了什么吗?8个线程应该更快。我有 8 核 CPU。

4

3 回答 3

1

一般来说,我不会比较没有优化的时间。用类似的东西编译

gcc -O3 -Wall -pedantic -fopenmp main.c

rand()函数在 Linux 中不是线程安全的(但它对 MSVC 很好,我猜 mingw32 使用与 MSVC 相同的 C 运行时库 MSVCRT)。您可以rand_r为每个线程使用不同的种子。请参阅openmp-program-is-slower-than-sequential-one

通常在并行化循环时尽量避免定义块大小。只需使用#pragma omp for schedule(shared). 您也不需要指定并行循环中的循环变量是私有的(i代码中的变量)。

试试下面的代码

#include <omp.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    int i, numIn, n;
    unsigned int seed;
    double x, y, pi;

    n = 1000000;
    numIn = 0;

    #pragma omp parallel private(seed, x, y) reduction(+:numIn) 
    {
        seed = 25234 + 17 * omp_get_thread_num();
        #pragma omp for
        for (i = 0; i <= n; i++) {
            x = (double)rand_r(&seed) / RAND_MAX;
            y = (double)rand_r(&seed) / RAND_MAX;
            if (x*x + y*y <= 1) numIn++;
        }
    }
    pi = 4.*numIn / n;
    printf("asdf pi %f\n", pi);
    return 0;
}

您可以在此处找到此代码的工作示例http://coliru.stacked-crooked.com/a/9adf1e856fc2b60d

于 2013-10-23T07:46:31.300 回答
1

请查看 http://people.sc.fsu.edu/~jburkardt/c_src/openmp/compute_pi.c 这可能是 pi 计算的一个很好的实现。

了解您的数据如何传播到不同的线程以及 openmp 如何将它们收集回来非常重要。通常,在多线程上运行的糟糕设计(具有跨线程的数据依赖关系)会导致执行速度比单线程慢。

于 2013-10-21T09:14:39.377 回答
1

rand()instdlib.h不是线程安全的。在多线程环境中使用它会导致其隐藏状态变量出现竞争条件,从而导致性能下降。

http://man7.org/linux/man-pages/man3/rand.3.html

事实上,以下代码可以很好地用作 OpenMP 演示。

$ gc -fopenmp -o pi pi.c -O3; time ./pi
pi: 3.141672

real    0m4.957s
user    0m39.417s
sys 0m0.005s

代码:

#include <stdio.h>
#include <omp.h>

int main()
{
    const int n=50000;
    const int NUM_THREADS=8;
    int numIn=0;

    #pragma omp parallel for reduction(+:numIn) num_threads(NUM_THREADS)
    for(int i = 0; i < n; i++) {
        double x = (double)i/n;
        for(int j=0;j<n; j++) {
            double y = (double)j/n;
            if (x*x + y*y <= 1) numIn++;
        }
    }

    printf("pi: %f\n",4.*numIn/n/n);
    return 0;
}
于 2013-10-21T09:14:50.880 回答