在我的代码中使用相同数量的线程减少 Openmp returns 不同的结果

Reduction in Openmp returns different results with the same number of threads in my code

我使用 "reduction" 的 openmp 代码与 运行 运行 的结果不同 return。

案例 1:使用 "reduction"

sum = 0;
omp_set_num_threads(4);
#pragma omp parallel for reduction(+:sum)
for(ii = 0; ii < 100; i++)
   sum = sum + func(ii);

with func(ii) 有副作用。事实上,func(ii) 使用另一个 calcul() 函数,这会导致并行执行中的竞争条件。我认为 calcul() 函数可能是导致此问题的原因。但是,我使用 "critical",结果始终相同,但此解决方案对性能不利。

案例 2:使用 "critical"

sum = 0;
#pragma omp parallel for
for(ii = 0; ii < 100; i++)
{
   #pragma omp critical
   sum = sum + func(ii);
}

使用 func(ii) 函数

func(int val) 
{
   read_file(val);
   calcul(); /*calculate something from reading_file(val)*/
   return val_fin;
}

请帮我解决一下?

非常感谢!

你在第二种情况下性能不佳的原因是整个循环体都在一个 critical 中,所以它实际上不能并行执行任何东西。

既然你说 calcul 函数中存在一些竞争条件,请考虑在 func 内的那一行中放置一个 critical 部分。这样,可以并行读取文件(这可能是 I/O 无论如何都会减慢您的执行速度)。

如果性能仍然很差,您将需要查看嵌套的 calcul 函数并尝试识别竞争条件。

基本上,您想将任何 critical 部分尽可能向下推或完全消除。如果归结为对共享变量进行非常简单的更新,在某些情况下,您可以改用 OpenMP atomic pragma,它具有更好的性能,但灵活性要差得多。

即使代码中的所有内容都是正确的,由于运算(加法)的关联性,您仍然可能从 OpenMP 缩减中得到不同的结果。 为了能够为给定数量的线程重现相同的结果,您需要通过将每个线程的部分总和存储在共享数组中来自行实现缩减。在并行区域之后,主线程可以添加这些结果。这种方法意味着线程总是执行相同的迭代,即静态调度策略。

相关问题: Order of execution in Reduction Operation in OpenMP