首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么并行版本比较慢?

为什么并行版本比较慢?
EN

Stack Overflow用户
提问于 2019-08-25 21:44:22
回答 1查看 83关注 0票数 2

我想在矩阵上应用特定的过滤器。(从头到尾)

Ai = 0.2 * (Ai + Ai+1 + Ai-1 + Ai + Ai)

例如,如果i,j是(矩阵中的第一个值),则在左边和上面使用零作为值。

我试图理解为什么并行版本的代码比顺序版本慢。

当我使用多线程进行计算时,我使用的事实是,在对角线上有独立的工作。为了简化滤波器的计算,我有意地将矩阵扩展为两行和两科尔(填充为零)。

我还尝试了各种尺寸的矩阵(高达7000x7000)。

我的问题:032

顺序版本:

代码语言:javascript
复制
for (int i = 1; i < r-1; i++) {
    for (int j = 1; j < c-1; j++) {
        arr[i][j] = 0.2f * (arr[i][j] + arr[i][j - 1] + arr[i - 1][j] + arr[i][j + 1] + arr[i + 1][j]); 
        }
    }

并行版本:

代码语言:javascript
复制
int n = r - 2;  
for (int slice = 0; slice < 2 * n - 1; ++slice) {     //along the diagonals
        int z = (slice < n) ? 0 : slice - n + 1;
        #pragma omp parallel for schedule(static) //spawns threads 
        for (int j = z; j <= slice - z; ++j) {
            pl_arr[j + 1][slice - j + 1] = 0.2f * (pl_arr[j + 1][slice - j + 1] + pl_arr[j + 1][slice - j] + pl_arr[j][slice - j + 1] + pl_arr[j + 1][slice - j + 1 + 1] + pl_arr[j + 1 + 1][slice - j + 1]);
        }
}

代码的其余部分:

代码语言:javascript
复制
int r = 7000, c = 7000;

r = r + 2;
c = c + 2;

/* initialize random seed: */
srand(time(NULL));

float **arr = (float **)malloc(r * sizeof(float *));
for (int i = 0; i < r; i++)
    arr[i] = (float *)malloc(c * sizeof(float));

float **pl_arr = (float **)malloc(r * sizeof(float *));
for (int i = 0; i < r; i++)
    pl_arr[i] = (float *)malloc(c * sizeof(float));


for (int i = 0; i < r; i++) {
    for (int j = 0; j < c; j++) {
        if ((i == 0) || (i == (r - 1)) || (j == 0) || (j == (c - 1)) ){
            arr[i][j] = 0;
            pl_arr[i][j] = 0;
        }
        else {
            arr[i][j] = rand() % 99  + 1;
            pl_arr[i][j] = arr[i][j];
        }
    }
}

#语用omp并行调度(静态)- for构造拆分for -循环,以便当前团队中的每个线程处理循环的不同部分。

结果: Paralle版本总是比顺序版本慢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-08-25 21:59:14

如果您计算出循环的顺序版本中发生了什么,您将看到内环访问顺序内存地址(或者更准确地说,访问三个内存范围,每个区域的地址按顺序访问)。

现代CPU是非常好的,并通过连续的内存地址。这就是为什么在许多用例中,std::vector可以反直觉地比std::list更快。

现在,对循环的并行版本也这样做。用铅笔在纸上算出每根线最后会碰到什么。看起来它是在垂直遍历矩阵,跨越多个单独分配的行。这不是连续的内存地址,而是到处都是;这不是最优的。

您可以简单地通过让每个线程捕获它正在突破的原始内存地址,并查看所有执行线程的组合捕获日志来完成这一任务;现在,将其与顺序版本的日志进行比较。

更糟的是:在典型的现代体系结构中,内存区域被划分为更大的块,称为“缓存线”。看起来,并行版本将有多个执行线程访问相邻的内存地址,其中许多线程将落入同一缓存线;当多个CPU执行单元必须写入同一高速缓存线时,即使写入每个缓存行中的不同地址,它们也必须执行一个复杂的歌舞例程,以避免踩到对方的脚趾。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57649958

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档