我正在尝试学习如何在 OpenMP 中使用归约,并且想知道是否可以使用归约来重写以下示例?
示例 A:求三个矩阵/张量的和
#include <Eigen/Dense>
#include <Eigen/SparseCore>
#include <Eigen/Sparse>
static const int nx = 128;
static const int ny = 128;
static const int nz = 128;
Eigen::Tensor<std::complex<double>, 3> Tensor1(nx,ny,nz);
Eigen::Tensor<std::complex<double>, 3> Tensor2(nx,ny,nz);
Eigen::Tensor<std::complex<double>, 3> Tensor3(nx,ny,nz);
for(int i = 0; i< nx; i++){
for(int j = 0; j< ny; j++){
for(int k = 0; k< nz; k++){
Sum(k,i,j) = (Tensor1(k,i,j) + Tensor2(k,i,j) + Tensor3(k,i,j));
}
}
}
示例 B:求 (AxB) 叉积的单独项:
#include <Eigen/Dense>
#include <Eigen/SparseCore>
#include <Eigen/Sparse>
static const int nx = 128;
static const int ny = 128;
static const int nz = 128;
double B[3] = {Bx,By,Bz};
Eigen::Tensor<std::complex<double>, 3> Ax(nx,ny,nz);
Eigen::Tensor<std::complex<double>, 3> Ay(nx,ny,nz);
Eigen::Tensor<std::complex<double>, 3> Az(nx,ny,nz);
Eigen::Tensor<std::complex<double>, 3> Termx(nx,ny,nz);
Eigen::Tensor<std::complex<double>, 3> Termy(nx,ny,nz);
Eigen::Tensor<std::complex<double>, 3> Termz(nx,ny,nz);
for(int i = 0; i< nx; i++){
for(int j = 0; j< ny; j++){
for(int k = 0; k< nz; k++){
Termx(k,i,j) = (Az(k,i,j) * By - Ay(k,i,j) * Bz);
Termy(k,i,j) = (Ax(k,i,j) * Bz - Az(k,i,j) * Bx);
Termz(k,i,j) = (Ay(k,i,j) * Bx - Ax(k,i,j) * By);
}
}
}
我还没有看到使用嵌套循环或矩阵/张量进行归约的示例,因此我不确定上述示例是否适用于归约。谢谢!
简短的回答是否定的。
更长的答案是你的例子不符合减少的目的的基本思想。
缩减通常用于所有线程写入单个输出的情况。对于一个非常简单的例子,考虑标准化一个大矩阵,只需将所有数字相加,然后将每个数字除以总和,使它们都在 0..1.
范围内#pragma omp parallel for
for (int i=0; i<n; i++)
for (int j=0; j<m; j++)
for (int k=0; k<o; k++)
sum += matrix[i][j][k];
这有一个问题:所有线程都写入
sum
。为了保持有意义的结果,OpenMP 运行时序列化对 sum
的访问,并且我们从并行运行的所有线程中获得的收益非常少(如果有的话)。
我们可以使用
reduction
来解决这个问题:
#pragma omp parallel for reduction(+:sum)
for (int i=0; i<n; i++)
for (int j=0; j<m; j++)
for (int k=0; k<o; k++)
sum += matrix[i][j][k];
这样,每个线程都会获得一个私有变量,用于存储其本地总和。然后,当线程完成时,它会进行归约(在本例中使用我们指定的运算符 -
+
)并将所有这些单独的值加在一起。
reduction
当所有线程一起工作以生成单个值时会有所帮助,并且我们可以通过让每个线程独立生成一个值,然后组合所有这些独立值来避免该值的压力。