C 并行BW和FW算法的最佳方法

C 并行BW和FW算法的最佳方法,c,multithreading,performance,parallel-processing,openmp,C,Multithreading,Performance,Parallel Processing,Openmp,我已经实现了求解L和U三角矩阵的BW和FW算法。 我实现的算法以串行方式运行得非常快,但我不知道这是否是并行化它的最佳方法。 我认为我已经考虑到了每一个可能的数据竞争(关于alpha),对吗 void solveInverse (double **U, double **L, double **P, int rw, int cw) { double **inverseA = allocateMatrix(rw,cw); double* x = allocateArray(rw);

我已经实现了求解L和U三角矩阵的BW和FW算法。 我实现的算法以串行方式运行得非常快,但我不知道这是否是并行化它的最佳方法。 我认为我已经考虑到了每一个可能的数据竞争(关于alpha),对吗

void solveInverse (double **U, double **L, double **P, int rw, int cw) {
    double **inverseA = allocateMatrix(rw,cw);
    double* x = allocateArray(rw);
    double* y = allocateArray(rw);
    
    double alpha;
    
    //int i, j, t;
    
    // Iterate along the column , so at each iteration we generate a column of the inverse matrix
    for (int j = 0; j < rw; j++) {
        
        // Lower triangular solve Ly=P
        y[0] = P[0][j];
        #pragma omp parallel for reduction(+:alpha)
        for (int i = 1; i < rw; i++) {
            alpha = 0;
            for (int t = 0; t <= i-1; t++)
                alpha += L[i][t] * y[t];
            y[i] = P[i][j] - alpha;
        }

        // Upper triangular solve Ux=P
        x[rw-1] = y[rw-1] / U[rw-1][rw-1];
        #pragma omp parallel for reduction(+:alpha)
        for (int i = rw-2; (i < rw) && (i >= 0); i--) {
            alpha = 0;
            
            for (int t = i+1; t < rw; t++)
                alpha += U[i][t]*x[t];
            x[i] = (y[i] - alpha) / U[i][i];
        }
        
        for (int i = 0; i < rw; i++)
            inverseA[i][j] = x[i];  
        }
    freeMemory(inverseA,rw);
    free(x);
    free(y);
}
void(双**U,双**L,双**P,整数rw,整数cw){
双**逆EA=分配矩阵(rw,cw);
double*x=分配通道(rw);
双*y=分配通道(rw);
双α;
//inti,j,t;
//沿着列进行迭代,因此在每次迭代中,我们生成一列逆矩阵
对于(int j=0;j


在与用户dreamcrash进行私人讨论后,我们得出了他在评论中提出的解决方案,为每个线程创建了一对向量
x
y
,这些线程将独立工作在一个列上。

在与OP讨论评论后(这些评论后来被删除),我们都得出结论:

您不需要减少
alpha
变量,因为在第一个
并行区域之外,它会再次初始化为零。相反,将
alpha
变量设为私有

而不是每个
j
迭代都有一个
并行区域
。您可以提取
并行区域
,以封装整个最外层循环,并使用
#pragma omp for
而不是
#pragma omp parallel for
。尽管如此,尽管通过这种方法我们减少了
并行r的数量从
rw
创建的egion
仅为1,通过此优化实现的加速应该没有那么显著,因为一个高效的OpenMP实现将使用一个线程池,其中线程在第一个
并行区域
上初始化,但在下一个
并行区域
上重用。因此,savi减少创建和销毁线程的开销

#pragma omp parallel
{
   for (int j = 0; j < rw; j++) 
   {
        y[0] = P[0][j];
        #pragma omp for
        for (int i = 1; i < rw; i++) {
            double alpha = 0;
            for (int t = 0; t <= i-1; t++)
               alpha += L[i][t] * y[t];
            y[i] = P[i][j] - alpha;
        }

        x[rw-1] = y[rw-1] / U[rw-1][rw-1];
        #pragma omp for
        for (int i = rw-2; (i < rw) && (i >= 0); i--) {
             double alpha = 0;
        
             for (int t = i+1; t < rw; t++)
                 alpha += U[i][t]*x[t];
             x[i] = (y[i] - alpha) / U[i][i];
        }
    
        #pragma omp for
        for (int i = 0; i < rw; i++)
           inverseA[i][j] = x[i];  
    }
}

在与OP讨论评论(之后删除)后,我们都得出结论:

您不需要减少
alpha
变量,因为在第一个
并行区域之外,它会再次初始化为零。相反,将
alpha
变量设为私有

而不是每个
j
迭代都有一个
并行区域
。您可以提取
并行区域
,以封装整个最外层循环,并使用
#pragma omp for
而不是
#pragma omp parallel for
。尽管如此,尽管通过这种方法我们减少了
并行r的数量从
rw
创建的egion
仅为1,通过此优化实现的加速应该没有那么显著,因为一个高效的OpenMP实现将使用一个线程池,其中线程在第一个
并行区域
上初始化,但在下一个
并行区域
上重用。因此,savi减少创建和销毁线程的开销

#pragma omp parallel
{
   for (int j = 0; j < rw; j++) 
   {
        y[0] = P[0][j];
        #pragma omp for
        for (int i = 1; i < rw; i++) {
            double alpha = 0;
            for (int t = 0; t <= i-1; t++)
               alpha += L[i][t] * y[t];
            y[i] = P[i][j] - alpha;
        }

        x[rw-1] = y[rw-1] / U[rw-1][rw-1];
        #pragma omp for
        for (int i = rw-2; (i < rw) && (i >= 0); i--) {
             double alpha = 0;
        
             for (int t = i+1; t < rw; t++)
                 alpha += U[i][t]*x[t];
             x[i] = (y[i] - alpha) / U[i][i];
        }
    
        #pragma omp for
        for (int i = 0; i < rw; i++)
           inverseA[i][j] = x[i];  
    }
}
#pragma omp parallel
{
   for (int j = 0; j < rw; j++) 
   {
        y[0] = P[0][j];
        #pragma omp for
        for (int i = 1; i < rw; i++) {
            double alpha = 0;
            for (int t = 0; t <= i-1; t++)
               alpha += L[i][t] * y[t];
            y[i] = P[i][j] - alpha;
        }

        x[rw-1] = y[rw-1] / U[rw-1][rw-1];
        #pragma omp for
        for (int i = rw-2; (i < rw) && (i >= 0); i--) {
             double alpha = 0;
        
             for (int t = i+1; t < rw; t++)
                 alpha += U[i][t]*x[t];
             x[i] = (y[i] - alpha) / U[i][i];
        }
    
        #pragma omp for
        for (int i = 0; i < rw; i++)
           inverseA[i][j] = x[i];  
    }
}
#pragma omp parallel for
for (int i = 1; i < rw; i++) {
    double alpha = 0;
    for (int t = 0; t <= i-1; t++)
        alpha += L[i][t] * y[t];
    y[i] = P[i][j] - alpha;
} 
#pragma omp parallel
{   
     double* x = allocateArray(rw);
     double* y = allocateArray(rw);

    #pragma omp for
    for (int j = 0; j < rw; j++) 
    {
        y[0] = P[0][j];
        for (int i = 1; i < rw; i++) {
            double alpha = 0;
            for (int t = 0; t <= i-1; t++)
               alpha += L[i][t] * y[t];
            y[i] = P[i][j] - alpha;
        }
        x[rw-1] = y[rw-1] / U[rw-1][rw-1];

        for (int i = rw-2; i >= 0; i--) {
             double alpha = 0;
             for (int t = i+1; t < rw; t++)
                 alpha += U[i][t]*x[t];
             x[i] = (y[i] - alpha) / U[i][i];
        }
        for (int i = 0; i < rw; i++)
           inverseA[i][j] = x[i];  
     }

    free(x);
    free(y);
}