我正在尝试使用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_pi
运行n = 1000000000
时,我得到了
真正的8m51.595s
用户4m14.004s
sys 60m59.533s
当我用一个线程运行它时,我得到了
真正的0m20.943s
用户0m20.881s
sys 0m0.000s
我错过了什么吗? 8个线程应该更快。我有8核CPU。
答案 0 :(得分:1)
请看一下 http://people.sc.fsu.edu/~jburkardt/c_src/openmp/compute_pi.c 这可能是pi计算的一个很好的实现。
了解数据如何传播到不同的线程以及openmp如何收集它们非常重要。通常,在多个线程上运行的错误设计(具有跨线程的数据依赖性)将导致执行速度比单个线程慢。
答案 1 :(得分:1)
rand()
中的 stdlib.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;
}
答案 2 :(得分:1)
一般情况下,我不会在没有优化的情况下比较时间。编译类似
gcc -O3 -Wall -pedantic -fopenmp main.c
rand()
函数在Linux中不是线程安全的(但它对MSVC没问题,我猜mingw32使用相同的C运行时库,MSVCRT,作为MSVC)。您可以为每个线程使用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;
}
找到此代码的有效示例