c - OpenMP并行的两种方法之间的区别
问题描述
我只想通过 OpenMP 的汇总来评估函数的集成,方法是使用数组来保存每个步骤中计算的每个值 > 取所有值的总和;并在没有数组的情况下取和。
代码是:
double f(double x)
{
return sin(x)*sin(x)/(x*x+1);
}
方法一
long i = 0;
const long NUM_STEP = 100000;
double sum[NUM_STEP];
double from = 0.0, to = 1.0;
double step = (to - from)/NUM_STEP;
double result = 0;
#pragma omp parallel for shared(sum) num_threads(4)
for(i=0; i<NUM_STEP; i++)
sum[i] = step*f(from+i*step);
for(i=0; i<NUM_STEP; i++)
result += sum[i];
printf("%lf", result);
方法二
long i = 0;
const long NUM_STEP = 100000;
double from = 0.0, to = 1.0;
double step = (to - from)/NUM_STEP;
double result = 0;
#pragma omp parallel for shared(result) num_threads(4)
for(i=0; i<NUM_STEP; i++)
result += step*f(from+i*step);
printf("%lf", result);
但结果相差太大。方法 1 给出了一个稳定的值,但方法 2 给出了一个可变值。这是一个例子:
方法一:0.178446
方法二:0.158738
METHOD 1 的值为真(由另一个工具检查)。
解决方案
TL;DR第一种方法没有竞争条件,而第二种方法有。
第一种方法没有竞争条件,而第二种方法有。即,在第一种方法中:
#pragma omp parallel for shared(sum) num_threads(4)
for(i=0; i<NUM_STEP; i++)
sum[i] = step*f(from+i*step);
for(i=0; i<NUM_STEP; i++)
result += sum[i];
每个线程将操作的结果保存在step*f(from+i*step);
数组的不同位置sum[i]
。之后,主线程依次减少数组中保存的值sum
,即:
for(i=0; i<NUM_STEP; i++)
result += sum[i];
实际上,您可以在此版本上进行一些改进;sum
而不是分配与数量相同大小的数组NUM_STEP
,您可以分配与线程数相同大小的数组,并且每个线程将保存在等于其的位置ID
,即:
int total_threads = 4;
double sum[total_threads];
#pragma omp parallel num_threads(total_threads)
{
int thread_id = omp_get_thread_num();
for(i=0; i<NUM_STEP; i++)
sum[thread_id] += step*f(from+i*step);
for(i=0; i< total_threads; i++)
result += sum[i];
}
尽管如此,最好的方法是实际修复第二种方法。
在第二种方法中,变量更新存在竞争条件result
:
#pragma omp parallel for shared(result) num_threads(4)
for(i=0; i<NUM_STEP; i++)
result += step*f(from+i*step);
因为该result
变量正在由多个线程以非线程安全的方式同时更新。
要解决这种竞争条件,您需要使用reduce子句:
#pragma omp parallel for reduction(+:result) num_threads(4)
for(i=0; i<NUM_STEP; i++)
result += step*f(from+i*step);
推荐阅读
- flutter - 如何在 Flutter 的 TextFormField 中显示拼写检查器(带下划线的错误拼写)?
- python - 在 Python 中运行“正常”代码时出现内存错误?
- gstreamer - 从 C++ 向 gstreamer 提供视频;如何获得工作时间
- excel - 创建新的 XML 元素作为现有元素的父节点
- java - 菜单页面上的按钮仅按特定顺序工作。(Android Studio - Java)
- c# - 资源文件 (.resx):值不在预期范围内
- python - 无法从 bash 函数访问 python 中的变量
- css - 如何从 React.js 中的 html 选择器动态更改背景图像 URL?
- python - 我正在寻找为阿拉伯语创建 OCR。我该如何开始?
- javascript - 调用 rerenderEvents 方法时如何过滤 fullcalendar v4 缓存事件?