为什么使用 OpenMP 库的代码在并行模式下比在顺序模式下运行的时间更长?

Why does code with the OpenMP library run longer in parallel mode than in sequential mode?

提问人:Viceversa 提问时间:11/7/2023 更新时间:11/7/2023 访问量:61

问:

我在使用 omp.h 库时遇到问题。任务是创建和测试一种使用高斯方法求解方程的算法,使用具有大量方程(从 500 个)的示例。串行和并行模式下执行时间的差异应该可见。我的代码在串行模式下显示 1.140253 秒,在并行模式下显示 4.394211 秒。我不明白错误在哪里

我在代码中将其用于并行模式,当我需要串行时,我会取消注释行omp_set_num_threads(1)

//omp_set_num_threads(1);
for (k = 0; k \< N - 1; k++)
{

        #pragma omp parallel for
        for (i = k + 1; i < N; i++)
        {
            
            d = A[i][k] / A[k][k];
            
            for (j = k; j < N; j++)
            {
                A[i][j] = A[i][j]- d * A[k][j];
            }
            B[i] = B[i] - d * B[k];
        }
    }

完整代码:

#include <iostream>
#include <ctime>
#include <omp.h>

const int N = 1000;
double A[N][N]; 
double B[N];    
double E[N];    

using namespace std;

void gauss(double A[N][N], double B[N], double E[N])
{
    
    int i, j, k;
    double d;
    //omp_set_num_threads(1);
    for (k = 0; k < N - 1; k++)
    {
        
        #pragma omp parallel for
        for (i = k + 1; i < N; i++)
        {
            
            d = A[i][k] / A[k][k];
            
            for (j = k; j < N; j++)
            {
                A[i][j] = A[i][j]- d * A[k][j];
            }
            B[i] = B[i] - d * B[k];
        }
    }
    
    for (i = N - 1; i >= 0; i--)
    {
        E[i] = B[i];
        
        for (j = i + 1; j < N; j++)
        {
            E[i] = E[i] - A[i][j] * E[j];
        }
        E[i]= E[i]/A[i][i];
    }
};

int main() {

    srand(time(NULL));
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            A[i][j] = -10 + rand() % 20;
        }
        B[i] = -10 + rand() % 20;
        
    }
    
    double start = omp_get_wtime();

    gauss(A, B, E);

    double end = omp_get_wtime();
    
    cout << "Time: " << fixed << (end - start) << " sec" << endl;

    return 0;
}
C++ OpenMP

评论

2赞 Homer512 11/7/2023
和变量是共享的,因此线程在写入它们时会踩到彼此的脚趾。在并行循环中声明它们dj
0赞 Jérôme Richard 11/7/2023
编程的一个黄金法则是声明接近其使用的变量(以避免这样的错误并提高可读性)。另一个黄金法则是在衡量性能之前检查结果。虚假程序可以;)快得多。
1赞 Jérôme Richard 11/7/2023
顺便说一句,请注意,该操作相当受内存限制,因此即使使用有效的正确代码,速度也应该很小。最重要的是,由于内部循环,线程之间存在工作不平衡。最慢的线程限制了代码的可伸缩性。
1赞 PierU 11/7/2023
@JérômeRichard我认为工作量在这里是平衡的,因为 k 在并行区域内保持不变。
0赞 Jérôme Richard 11/7/2023
确实@PierU。我快速阅读了代码。不好意思。

答: 暂无答案