亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

減少OpenMP中的數組

減少OpenMP中的數組

C++
拉莫斯之舞 2019-10-11 10:12:29
我正在嘗試并行化以下程序,但不知道如何在數組上進行歸約。我知道這是不可能的,但是有替代方法嗎?謝謝。(我增加了對m的歸納,這是錯誤的,但想對如何做提出建議。)#include <iostream>#include <stdio.h>#include <time.h>#include <omp.h>using namespace std;int main (){  int A [] = {84, 30, 95, 94, 36, 73, 52, 23, 2, 13};  int S [10];  time_t start_time = time(NULL);  #pragma omp parallel for private(m) reduction(+:m)  for (int n=0 ; n<10 ; ++n ){    for (int m=0; m<=n; ++m){      S[n] += A[m];    }  }  time_t end_time = time(NULL);  cout << end_time-start_time;  return 0;}
查看完整描述

3 回答

?
慕桂英4014372

TA貢獻1871條經驗 獲得超13個贊

是的,可以使用OpenMP進行陣列縮減。在Fortran中,它甚至對此具有構造。在C / C ++中,您必須自己做。這有兩種方法。


第一種方法S為每個線程創建的私有版本,并行填充它們,然后將它們合并到S關鍵部分(請參見下面的代碼)。第二種方法創建一個具有10 * nthread個尺寸的數組。并行填充此數組,然后在S不使用關鍵節的情況下將其合并到其中。第二種方法要復雜得多,如果不小心,可能會出現緩存問題,尤其是在多插槽系統上。有關更多詳細信息,請參見此填充直方圖(數組縮減)與OpenMP并行使用,而無需使用關鍵部分


第一種方法


int A [] = {84, 30, 95, 94, 36, 73, 52, 23, 2, 13};

int S [10] = {0};

#pragma omp parallel

{

    int S_private[10] = {0};

    #pragma omp for

    for (int n=0 ; n<10 ; ++n ) {

        for (int m=0; m<=n; ++m){

            S_private[n] += A[m];

        }

    }

    #pragma omp critical

    {

        for(int n=0; n<10; ++n) {

            S[n] += S_private[n];

        }

    }

}

第二種方法


int A [] = {84, 30, 95, 94, 36, 73, 52, 23, 2, 13};

int S [10] = {0};

int *S_private;

#pragma omp parallel

{

    const int nthreads = omp_get_num_threads();

    const int ithread = omp_get_thread_num();


    #pragma omp single 

    {

        S_private = new int[10*nthreads];

        for(int i=0; i<(10*nthreads); i++) S_private[i] = 0;

    }

    #pragma omp for

    for (int n=0 ; n<10 ; ++n )

    {

        for (int m=0; m<=n; ++m){

            S_private[ithread*10+n] += A[m];

        }

    }

    #pragma omp for

    for(int i=0; i<10; i++) {

        for(int t=0; t<nthreads; t++) {

            S[i] += S_private[10*t + i];

        }

    }

}

delete[] S_private;


查看完整回答
反對 回復 2019-10-11
?
慕萊塢森

TA貢獻1810條經驗 獲得超4個贊

關于Zboson的答案,我有兩點評論:

1.方法1當然是正確的,但是歸約循環實際上是串行運行的,因為#pragma ompcritical必不可少,因為部分線程對于每個線程都是局部的,并且相應的歸約具有通過線程來完成矩陣。

2.方法2:初始化循環可以移到單個部分的外面,因此可以并行化。


以下程序使用openMP v4.0用戶定義的還原工具實現 陣列還原:


/* Compile with:

     gcc -Wall -fopenmp -o ar ar.c

   Run with:

     OMP_DISPLAY_ENV=TRUE OMP_NUM_THREADS=10 OMP_NESTED=TRUE ./ar

*/

#include <stdio.h>

#include <omp.h>

struct m10x1 {int v[10];};

int A [] =       {84, 30, 95, 94, 36, 73, 52, 23, 2, 13};  

struct m10x1 S = {{ 0,  0,  0,  0,  0,  0,  0,  0, 0,  0}};

int n,m=0;


void print_m10x1(struct m10x1 x){

  int i;

  for(i=0;i<10;i++) printf("%d ",x.v[i]);

  printf("\n");

}


struct m10x1 add_m10x1(struct m10x1 x,struct m10x1 y){

  struct m10x1 r ={{ 0,  0,  0,  0,  0,  0,  0,  0, 0,  0}};

  int i;

  for (i=0;i<10;i++) r.v[i]=x.v[i]+y.v[i];

  return r;

}


#pragma omp declare reduction(m10x1Add: struct m10x1: \

omp_out=add_m10x1(omp_out, omp_in)) initializer( \

omp_priv={{ 0,  0,  0,  0,  0,  0,  0,  0, 0,  0}} )


int main ()

{

  #pragma omp parallel for reduction(m10x1Add: S)

  for ( n=0 ; n<10 ; ++n )

    {

      for (m=0; m<=n; ++m){

        S.v[n] += A[m];

      }

    }

  print_m10x1(S);

}

這完全按照OpenMP 4.0功能第97頁的復數減少示例進行。


盡管并行版本可以正常工作,但可能存在性能問題,我尚未調查:


add_m10x1輸入和輸出按值傳遞。

add_m10x1中的循環按順序運行。

所說的“性能問題”是我自己造成的,完全不介紹它們就很簡單:


add_m10x1的參數應通過引用傳遞(通過C中的指針,C ++中的引用)

add_m10x1中的計算應就位。

應該將add_m10x1聲明為void,并刪除return語句。結果通過第一個參數返回。

應該相應地減少聲明減少編譯指示,合并器應該只是函數調用而不是賦值(v4.0規范p181第9,10行)。

add_m10x1中的for循環可以通過omp parallel for pragma并行化

應啟用并行嵌套(例如,通過OMP_NESTED = TRUE)

然后,代碼的修改部分為:


void add_m10x1(struct m10x1 * x,struct m10x1 * y){

  int i;

  #pragma omp parallel for

  for (i=0;i<10;i++) x->v[i] += y->v[i];

}


#pragma omp declare reduction(m10x1Add: struct m10x1: \

add_m10x1(&omp_out, &omp_in)) initializer( \

omp_priv={{ 0,  0,  0,  0,  0,  0,  0,  0, 0,  0}} )


查看完整回答
反對 回復 2019-10-11
  • 3 回答
  • 0 關注
  • 777 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號