我需要计算 z
值,将它们放入数组 B
和 s2
。
我尝试使用 omp parallel for
并行化处理。
我看到的一个问题是,如果我不将 B[i][j] += z
和 s2[i] += z
语句放在 critical
部分,我看到生成了很多 NaN
值。
只是想知道是否有办法将 z
值写入单独的数组(每个线程一个数组)并在最后合并它们。
非常感谢任何帮助。
#pragma omp parallel
{
double z;
#pragma omp parallel for
for(int t=1; t<n; t++) {
double phi_i[N];
double obs_j_seq_t[N];
for(int i=0; i<N; i++) {
for(int j=0; j<N; j++) {
z=phi_i[i]*trans[i*N + j]*obs_j_seq_t[j]*beta[t*N+j]/c[t];
#pragma omp critical
{
B[i][j] += z;
s2[i] += z;
}
}
}
}
}
最佳答案
您的代码暴露了一些问题,每个问题都是其性能和/或有效性的潜在 killer :
- 首先使用
#pragma omp parallel
,然后添加#pragma omp parallel for
。这意味着您正在尝试生成嵌套并行性(另一个并行区域内的并行区域)。首先,这是一个坏主意,其次,默认情况下禁用。因此,您的第二个parallel
指令将被忽略,您的循环中的工作永远不会被分发,并由您使用初始parallel
指令生成的所有线程完全执行。因此,所有线程同时将结果写入B
和s2
时存在竞争条件。您通过添加critical
部分解决了问题,但从根本上说,代码是错误的。 - 即使您没有这个初始的
parallel
指令或启用嵌套并行性,您的代码也会因为以下原因而出错:- 您的
z
变量在第二个parallel
区域的线程之间共享
,因为它被所有线程修改,所以它的值为一旦在该区域中产生了一个以上的线程,就未定义。 - 更根本的是,您尝试在
t
上并行化循环,但解决方案是在i
上索引的。这意味着所有线程将竞争更新相同的索引,再次导致竞争条件和无效结果。您可以再次使用critical
指令来解决这个问题,但这只会使代码变得非常慢。您最好将i
上的循环并行化(同时可能交换t
和i
上的循环,将后者放在最外层)。
- 您的
您的代码可能会变成这样(未测试):
#pragma omp parallel for
for(int i=0; i<N; i++) {
for(int t=1; t<n; t++) {
double phi_i[N]; // I guess these need some initialization
double obs_j_seq_t[N]; // Idem
for(int j=0; j<N; j++) {
double z=phi_i[i]*trans[i*N + j]*obs_j_seq_t[j]*beta[t*N+j]/c[t];
B[i][j] += z;
s2[i] += z;
}
}
}
关于c++ - : How to make threads write to private arrays and merge all the arrays once all the threads finished processing 并行 omp,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40289248/