我正在处理阶乘函数。我必须使用OpenMP编写并行版本。
double sequentialFactorial(const int N) {
double result = 1;
for(int i = 1; i <= N; i++) {
result *= i;
}
return result;
}
众所周知,可以使用归约技术有效地并行化此算法。
我知道存在reduction
子句(standard§§2.15.3.6)。
double parallelAutomaticFactorial(const int N) {
double result = 1;
#pragma omp parallel for reduction(*:result)
for (int i=1; i <= N; i++)
result *= i;
return result;
}
但是,我想尝试实施减少“手工”技术。
double parallelHandmadeFactorial(const int N) {
// maximum number of threads
const int N_THREADS = omp_get_max_threads();
// table of partial results
double* partial = new double[N_THREADS];
for(int i = 0; i < N_THREADS; i++) {
partial[i] = 1;
}
// reduction tecnique
#pragma omp parallel for
for(int i = 1; i <= N; i++) {
int thread_index = omp_get_thread_num();
partial[thread_index] *= i;
}
// fold results
double result = 1;
for(int i = 0; i < N_THREADS; i++) {
result *= partial[i];
}
delete partial;
return result;
}
我希望最后两个代码片段的性能非常相似,并且比第一个更好。但是,平均表现为:
Sequential Factorial 3500 ms
Parallel Handmade Factorial 6100 ms
Parallel Automatic Factorial 600 ms
我想念什么吗?
由于@Gilles和@ P.W,此代码可以正常工作
double parallelNoWaitFactorial(const int N) {
double result = 1;
#pragma omp parallel
{
double my_local_result = 1;
// removing nowait does not change the performance
#pragma omp for nowait
for(int i = 1; i <= N; i++)
my_local_result *= i;
#pragma omp atomic
result *= my_local_result;
}
return result;
}
答案 0 :(得分:3)
如果数组元素碰巧共享一条缓存行,则将导致false sharing,这进一步导致性能下降。
为避免这种情况:
double partial
而不是double
数组
partial
。 partial
结果来计算关键区域中的最终result
result
应该是非并行区域专用的变量。关键区域将如下所示:
#pragma omp critical
result *= partial;