我想实现OpenMP来并行化我的代码。我从一个非常基本的例子开始,了解它是如何工作的,但我错过了一些东西......
所以,我的例子看起来像这样,没有并行化:
int main() {
...
for (i = 0; i < n-1; i++) {
u[i+1] = (1+h)*u[i]; // Euler
v[i+1] = v[i]/(1-h); // implicit Euler
}
...
return 0;
}
我省略了“......”中的某些部分,因为它们不相关。它有效,如果我在文件上打印u[]
和v[]
数组,我会得到预期的结果。
现在,如果我尝试通过添加以下内容来并行化它:
#include <omp.h>
int main() {
...
omp_set_num_threads(2);
#pragma omp parallel for
for (i = 0; i < n-1; i++) {
u[i+1] = (1+h)*u[i]; // Euler
v[i+1] = v[i]/(1-h); // implicit Euler
}
...
return 0;
}
代码编译并运行程序,但 u[]
和 v[]
数组中有一半是零。
如果我设置 omp_set_num_threads( 4 )
,我会得到四分之三的零。
如果我设置 omp_set_num_threads( 1 )
,我会得到预期的结果。
所以它看起来只有第一个线程正在执行,而不是其他线程......
我做错了什么?
答案 0 :(得分:1)
OpenMP假定循环的每次迭代都独立于其他循环。当你这样写:
i
循环的迭代i+1
正在修改迭代i+1
。同时,迭代t+1
可能同时发生。
除非你能使迭代独立,否则这不是并行的好用例。
而且,如果你考虑一下Euler的方法所做的事情,那么显然不可能以这种方式并行处理你正在处理的代码。欧拉的方法基于时间t
处的信息在时间t+1
计算系统的状态。由于您在不知道首先了解t
的情况下无法知道Intent intent = new Intent(Activity1.this, Activity2.class);
intent.putExtra("data1" , "data_value_1");
intent.putExtra("data2" , "data_value_2");
startActivity(intnent);
处的内容,因此无法在欧拉方法的迭代中进行并行化。
答案 1 :(得分:1)
欢迎来到并行(或&#34;只是&#34; - 并发)多个计算现实。
处理循环的任何非顺序计划都会出现隐藏(未正确处理)数据泄露的问题 - { - access | -值} 及时完整。
纯粹的[SERIAL]
处理流程没有这种危险,因为主要序列化的步骤间接地引入(正确的执行任务的严格顺序除外)一步一个接一个地作为序列)订单,其中没有机会&#34;触摸&#34;相同的内存位置同时两次或多次。
这&#34;安心&#34;一旦进程进入"just"-[CONCURRENT]
或true-[PARALLEL]
处理,就会无意中丢失。
突然间有一个几乎随机的顺序(在&#34;只是&#34; - [CONCURRENT]
)或主要&#34;立即&#34;奇点(避免任何原始含义&#34;顺序&#34; - 在真正的[PARALLEL]
代码执行模式的情况下 - 像机器人一样,具有6DoF,到达每个轨迹点真 - [PARALLEL]时尚,以纯粹的[SERIAL]
方式并行驱动所有6个DoF轴,而不是一个接一个地驱动所有6个轴,而不是现在的某个 - 其他 - 以后 - 和 - 因为机器人手臂的三维轨迹将变得难以预测,并且经常在汽车装配上发生相互碰撞,所以它只能以一种方式进入...... [CONCURRENT]
方式线......)。
使用防御工具,称为原子操作,或主要方法 - 设计(b)无锁算法,尽可能,或明确表示信号和坐标读取和写入(确保以超时和降低性能为代价),以保证如果保护步骤(确保所有&#34;旧的&#34; -writes安全地通过&#34;通过&#34;在任何&#34; next&#34; -reads继续抓住&#34;右&#34; -value)之前没有被编码(如如上所述。
使用像OpenMP这样的工具来解决问题,它不会带来任何好处,这将导致花费时间和降低性能(因为需要处理所有与工具相关的开销,而并行性的净效果几乎为零)在这种情况下,算法不允许任何并行性的享受),所以最终会有一种方式比最终得到的更多。
了解OpenMP最佳实践的一个好点可能来自劳伦斯利弗莫尔国家实验室(确实非常称职)和类似的publications on using OpenMP.
答案 2 :(得分:1)
在并行化代码之前,您必须确定其并发性,即同时发生逻辑的任务集,然后找出一种方法来实现它们< em>实际上并行发生。
如上所述,由于其性质上没有并发性,因此这不是一个应用并行性的好例子。由于所谓的竞争条件,试图使用这样的并行性将导致错误的结果。
如果您只是想了解OpenMP的工作原理,请尝试提供一些示例,您可以清楚地识别出独立于概念的任务。我能想到的最简单的一个就是通过积分来计算曲线下面积。
答案 3 :(得分:1)
u[i+1] = (1+h)*u[i];
v[i+1] = v[i]/(1-h);
相当于
u[i] = pow((1+h), i)*u[0];
v[i] = v[0]*pow(1.0/(1-h), i);
因此您可以像这样将代码并行化
#pragma omp parallel for
for (int i = 0; i < n; i++) {
u[i] = pow((1+h), i)*u[0];
v[i] = v[0]*pow(1.0/(1-h), i);
}
如果你想减轻pow
函数的成本,你可以每个线程执行一次,而不是像他的那样(从t << n
开始)每次迭代执行一次。
#pragma omp parallel
{
int nt = omp_get_num_threads();
int t = omp_get_thread_num();
int s = (t+0)*n/nt;
int f = (t+1)*n/nt;
u[s] = pow((1+h), s)*u[0];
v[s] = v[0]*pow(1.0/(1-h), s);
for(int i=s; i<f-1; i++) {
u[i+1] = (1+h)*u[i];
v[i+1] = v[i]/(1-h);
}
}
您还可以编写自己的pow(double, int)
函数,针对整数幂进行优化。
请注意,我使用的关系实际上并非100%等效,因为浮点运算不是关联的。这通常不是问题,但是应该注意的事情。